hdu1494 跑跑卡丁车(动态规划)
Description
跑跑卡丁车是时下一款流行的网络休闲游戏,你可以在这虚拟的世界里体验驾驶的乐趣。这款游戏的特别之处是你可以通过漂移来获得一种
加速卡,用这种加速卡可以在有限的时间里提高你的速度。为了使问题简单化,我们假设一个赛道分为L段,并且给你通过每段赛道的普通耗时Ai和用加速卡的耗时Bi。加速卡的获得机制是:普通行驶的情况下,每通过1段赛道,可以获得20%的能量(N2O).能量集满后获得一个加速卡(同时能量清0).加速卡最多可以储存2个,也就是说当你有2个加速卡而能量再次集满,那么能量清零但得不到加速卡。一个加速卡只能维持一段赛道,游戏开始时没有加速卡。
问题是,跑完n圈最少用时为多少?
加速卡,用这种加速卡可以在有限的时间里提高你的速度。为了使问题简单化,我们假设一个赛道分为L段,并且给你通过每段赛道的普通耗时Ai和用加速卡的耗时Bi。加速卡的获得机制是:普通行驶的情况下,每通过1段赛道,可以获得20%的能量(N2O).能量集满后获得一个加速卡(同时能量清0).加速卡最多可以储存2个,也就是说当你有2个加速卡而能量再次集满,那么能量清零但得不到加速卡。一个加速卡只能维持一段赛道,游戏开始时没有加速卡。
问题是,跑完n圈最少用时为多少?
Input
每组输入数据有3行,第一行有2个整数L(0<L<100),N(0<N<100)分别表示一圈赛道分为L段和有N圈赛道,接下来两行分别有L个整数Ai和Bi
(Ai > Bi).
(Ai > Bi).
Output
对于每组输入数据,输出一个整数表示最少的用时.
Sample Input
18 1 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 8 8 8 8 8 8 8 8 8 8 8 8 8 8 1 1 8 8
Sample Output
145 对于sample这组数据,你可以先在普通情况下行驶前14段,这时你有2个加速卡以及80%的能量(N2O).在第15和16段用掉2个加速卡,通过第 17段赛道后又可以得到一个加速卡,在第18段赛道使用.
这道本来很简单的dp,wa了一下午,刚开始的状态还是想的比较快的 dp[i][j][k]代表 第i段,有j个加速卡,现在的能量为k。然后就开始了无尽的wa之旅,wa点其实就三个。
首先我把数组给开小了....正好开了dp[10100][3][100],这个错误通过对拍,然后手推错误数据发现了,当时就想打自己,本来以为能ac了,结果还是wa,然后我一口气对拍了10w组b=1的数据,竟然没有错。然后又对拍了1000组 b=5时候的数据...竟然几乎一个对的都没有,仔细一看,原来是把n圈变成n*l段时,把l误用为了n,又想打自己,本来以为可以ac了,结果还是wa,继续对拍,b=5的时候 有3组数据,分别比正确答案多1 . 2 .3 这时候我确定肯定是状态转移出错了。刚开始的状态转移是这样的,当k==0时,情况可能是,在上一段能量到了80,这段攒了一个加速卡,还可能是,上一段有加速卡,并且用了且当时k==0,所以继续用加速卡,这段依然不增加能量,k==0.k>0时,情况可能是,如果有两张能量卡,那么说明是正常走了一段,如果小于两张,则可能是正常走了一段,或者用了一张加速卡。
经过仔细思考,我发现是因为我漏掉了一种我自认为不可能的情况,那就是有了两张卡,然后能量到了100,然后能量变为0,我本来想的是,卡不用白不用,让能量清0肯定不是最优解,但仔细想的话,如果你不想浪费这张新加速卡,就必须在到100的时候用掉原来的某张加速卡,这肯定是有各种反例的。所以这个题教会了我,动态规划的转移方程一定要写出所有符合条件的,不管你认为亏不亏,合不合理。就算亏他也会在转移中被更新,所以要写全。
1 #include<cstdio> 2 3 #include<string.h> 4 5 #include<algorithm> 6 7 #define inf 0x3f3f3f3f 8 9 const int maxn=10000; 10 11 using namespace std; 12 13 int l,n,ans; 14 15 int dp[maxn+10][5][120]; 16 17 int a[maxn+10]; 18 19 int b[maxn+10]; 20 21 int main() 22 { 23 /* freopen("e://duipai//data.txt","r",stdin); 24 freopen("e://duipai//out2.txt","w",stdout);*/ 25 while(scanf("%d%d",&l,&n)!=EOF){ 26 ans=inf; 27 memset(dp,inf,sizeof(dp)); 28 for(int i=1;i<=l;i++){ 29 scanf("%d",&a[i]); 30 for(int j=1;j<n;j++){ 31 a[j*l+i]=a[i]; 32 } 33 } 34 for(int i=1;i<=l;i++){ 35 scanf("%d",&b[i]); 36 for(int j=1;j<n;j++){ 37 b[j*l+i]=b[i]; 38 } 39 } 40 dp[0][0][0]=0; 41 for(int i=1;i<5;i++){ 42 dp[i][0][i*20]=dp[i-1][0][(i-1)*20]+a[i]; 43 } 44 for(int i=5;i<=n*l;i++){ 45 for(int j=0;j<=2;j++){ 46 for(int k=0;k<100;k+=20){ 47 if(i<10&&j>1) continue; 48 if(!k){ 49 if(j==1){ 50 dp[i][j][k]=min(dp[i][j][k],min(dp[i-1][j-1][80]+a[i],dp[i-1][j+1][k]+b[i])); 51 } else if(j==2){ 52 dp[i][j][k]=min(dp[i][j][k],min(dp[i-1][j-1][80]+a[i],dp[i-1][j][80]+a[i])); 53 } else if(!j) dp[i][j][k]=min(dp[i][j][k],dp[i-1][j+1][k]+b[i]); 54 } else if(k){ 55 if(j==2){ 56 dp[i][j][k]=min(dp[i][j][k],dp[i-1][j][k-20]+a[i]); 57 } 58 if(j<2){ 59 dp[i][j][k]=min(dp[i][j][k],min(dp[i-1][j][k-20]+a[i],dp[i-1][j+1][k]+b[i])); 60 } 61 } 62 } 63 } 64 } 65 for(int i=0;i<=2;i++){ 66 for(int j=0;j<100;j+=20){ 67 ans=min(ans,dp[n*l][i][j]); 68 } 69 } 70 printf("%d\n",ans); 71 } 72 return 0; 73 }