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 }
				
时间: 2024-11-06 21:04:29

hdu1494 跑跑卡丁车(动态规划)的相关文章

HDU ACM 1494 跑跑卡丁车动态规划

分析:L段,N圈,则总共可表示为L*N段,用增加20%的能量表示一个状态,则可表示20%,40%,%60...,共15个,注意第15个时要清零到两个能量卡:用dp[i][j]表示在第i段能量为j的已用时的最少时间.则可得到方程1.不用能量卡时dp[i][j]=min(dp[i][j],dp[i-1][j-1]+a[i-1]:用能量卡时dp[i][j-5]=min(dp[i][j-5],dp[i-1][j]+b[i-1]). #include<iostream> using namespace

hdu 1494 跑跑卡丁车(动态规划)

Problem Description 跑跑卡丁车是时下一款流行的网络休闲游戏,你可以在这虚拟的世界里体验驾驶的乐趣.这款游戏的特别之处是你可以通过漂移来获得一种加速卡,用这种加速卡可以在有限的时间里提高你的速度.为了使问题简单化,我们假设一个赛道分为L段,并且给你通过每段赛道的普通耗时Ai和用加速卡的耗时Bi.加速卡的获得机制是:普通行驶的情况下,每通过1段赛道,可以获得20%的能量(N2O).能量集满后获得一个加速卡(同时能量清0).加速卡最多可以储存2个,也就是说当你有2个加速卡而能量再次

Leetcode 494 Target Sum 动态规划 背包+滚动数据

这是一道水题,作为没有货的水货楼主如是说. 题意:已知一个数组nums {a1,a2,a3,.....,an}(其中0<ai <=1000(1<=k<=n, n<=20))和一个数S c1a1c2a2c3a3......cnan = S, 其中ci(1<=i<=n)可以在加号和减号之中任选. 求有多少种{c1,c2,c3,...,cn}的排列能使上述等式成立. 例如: 输入:nums is [1, 1, 1, 1, 1], S is 3. 输出 : 5符合要求5种

活动选择的贪心算法与动态规划(未完成)

// greedy_algorithm.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> #include<queue> using namespace std; #define NofActivity 11 int c[NofActivity + 1][NofActivity + 1]; int reme[NofActivity + 1][NofActivity + 1]; //活动的

求不相邻金币相加和的最大值--动态规划1

求不相邻金币相加和的最大值. 输入n个金币的金币面值(正数自定义),求这些金币不相邻和的最大值. 动态规划问题1 设f(n)为第n个金币数的最大值,f(0)=0,f(1)=a[1],输入的数组从下标为1开始. f(n)=max{a[n]+f(n-2),f(n-1)}. 代码如下: import java.util.Scanner; public class Jin_bi_zui_da_zhi { public static void main(String[] args) { Scanner s

[动态规划] 黑客的攻击 Hacker&#39;s CrackDown Uva 11825

抽象为数学模型就是,  取尽可能多的互不相交的子集 ,  使得每一个子集都能覆盖全集 #include <algorithm> #include <cstring> #include <cstdio> using namespace std; int n; int P[1000],cover[1000],f[1000]; int main(){ scanf("%d", &n); for (int i = 0; i < n;i++) {

Beauty Of algorithms(七)动态规划 钢条分割 矩阵链乘 最长公共子序列 最优二叉树

1.动态规划                动态规划的方法与方法类似,英文"dynamic programming",这里的programming不是程序的意思,而是一种表格法.都是通过组合子问题的解来解决原问题,分治方法将划分为互不相交的子问题,递归的求解子问题,再将它们的解组合起来求出原问题的解.与之相反动态规划应用于子问题的重叠情况,即不同的子问题具有公共的子问题,子问题的求解是递归进行 的,将其划分为更小的子问题,动态规划,每个子问题只求解一次,将其保存在表格中,从而无需每次求

Hdoj 1176 免费馅饼 【动态规划】

免费馅饼 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 26110    Accepted Submission(s): 8905 Problem Description 都说天上不会掉馅饼,但有一天gameboy正走在回家的小径上,忽然天上掉下大把大把的馅饼.说来gameboy的人品实在是太好了,这馅饼别处都不掉,就掉落在他身旁的1

Fibonacci斐波拉契数列----------动态规划DP

n==10 20 30 40 50 46 体验一下,感受一下,运行时间 #include <stdio.h>int fib(int n){ if (n<=1)     return 1; else            return fib(n-1)+fib(n-2); }int main( ){ int n; scanf("%d",&n); printf("%d\n" ,fib(n) );} 先 n==10 20 30 40 50 46