[NOIP2009]普及組T4 道路遊戲
阿新 • • 發佈:2019-01-03
題意:在環形公路上,給定n個工廠製造機器人的花費以及n條道路每個時刻的金幣數,一個時刻必須有也只能有一個機器人在公路上收集金幣,求m時刻後能收集的最多金幣。這題題意很明確,顯然是dp,這裡我們講的是貪心的做法,另外還有單調佇列的做法。
我們要儘可能多地收集金幣,就得考慮第i時刻買不買機器人。所以我們要分清什麼情況下買機器人,什麼情況下不買機器人。
先介紹一下程式碼中要用到的陣列及變數。
dp[i][j] 表示i時刻在j工廠能收集到的最多金幣
step[i][j] 表示在i時刻在j工廠的機器人已經走的步數
pre[i] 表示i工廠前一個工廠編號,當i>1時,pre[i]=i-1;當i=1時,pre[i]=n
mx 表示當前時刻能得到的最多金幣
pastmx 表示前一個時刻能得到的最多金幣
買機器人的情況:
(1)step[i-1][pre[j]]=p,即表示上個機器人已經走了p步,機器人不能再走了;(2)pastmx-cost[pre[j]]≥dp[i-1][pre[j]],即表示在i-1時刻的某個工廠收集到金幣減去j工廠前一個工廠製造的花費仍大於等於i-1時刻到達j工廠前一個工廠收集到的金幣數,也就是說pastmx-dp[i-1][pre[j]]足以支付pre[j]的製造費用,此時買機器人能走的步數比之前多,顯然更優。
不買機器人的情況:
不買機器人就是除去買機器人的情況,step加1,能獲得的金幣增加
#include<stdio.h>
#include<algorithm>
#include<iostream>
#define oo 2000000000
#define M 1005
using namespace std;
template <class T>
inline void Rd(T &res){
char c;res=0;int k=1;
while(c=getchar(),c<48&&c!='-');
if(c=='-'){k=-1;c='0';}
do{
res=(res<<3)+(res<<1 )+(c^48);
}while(c=getchar(),c>=48);
res*=k;
}
int n,m,p;
int val[M][M];//i時刻第j段公路出現的金幣數
int cost[M];//第i個工廠的製造費用
int dp[M][M];//i時刻在j工廠的最多金幣
int step[M][M];//i時刻在j工廠的機器人走的步數
int pre[M];//i工廠前一個工廠的編號
int pastmx,mx;
int main(){
Rd(n);Rd(m);Rd(p);
for(int j=1;j<=n;j++)
for(int i=1;i<=m;i++)
Rd(val[i][j]);
for(int i=1;i<=n;i++){
Rd(cost[i]);
pre[i]=i-1;
}
pre[1]=n;
mx=-1<<30;
for(int i=1;i<=n;i++){
step[1][i]=1;
dp[1][i]=val[1][pre[i]]-cost[pre[i]];
mx=max(mx,dp[1][i]);
}
pastmx=mx;
for(int i=2;i<=m;i++){
mx=-1<<30;
for(int j=1;j<=n;j++){
if(step[i-1][pre[j]]<p&&pastmx-cost[pre[j]]<dp[i-1][pre[j]]){
step[i][j]=step[i-1][pre[j]]+1;
dp[i][j]=dp[i-1][pre[j]]+val[i][pre[j]];
}else{
step[i][j]=1;
dp[i][j]=pastmx-cost[pre[j]]+val[i][pre[j]];
}
mx=max(mx,dp[i][j]);
}
pastmx=mx;
}
printf("%d\n",mx);
return 0;
}
剛看到這題的時候,直接敲了O(nmp)的DP,沒往貪心的方面想,所以沒做出來,現在想想還是很清晰的。