hdu1494 跑跑卡丁车(动态规划)

Description

跑跑卡丁车是时下一款流行的网络休闲游戏,你可以在这虚拟的世界里体验驾驶的乐趣。这款游戏的特别之处是你可以通过漂移来获得一种 
加速卡,用这种加速卡可以在有限的时间里提高你的速度。为了使问题简单化,我们假设一个赛道分为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). 

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 }

 


posted @ 2016-08-05 18:56  GeniusYang  阅读(592)  评论(0编辑  收藏  举报