http://acm.hdu.edu.cn/showproblem.php?pid=1494
题意:跑跑卡丁车的背景,每一圈被分n段跑,没跑完一段积累20%能量,能量满了变换一个加速卡,最多两张卡,多了会爆同时能量变成0,卡不变。
每一段用加速卡和不用加速卡的时间分别给你,问整场跑下来最小时间,就是求最优时刻用加速卡,每个状态转移的关系很清晰,很明显动态规划可以一做。
最初做这题对dp状态定义的摸不着头脑三维,二维的...当初先看一个大牛题解 用的是 变形的01背包问题。
把每个加速卡看成一个背包,重量是5。
详见代码。
#include <fstream> #include <iostream> #include <string> #include <complex> #include <math.h> #include <set> #include <vector> #include <map> #include <queue> #include <stdio.h> #include <stack> #include <algorithm> #include <list> #include <ctime> #include <memory.h> #include <ctime> #include <assert.h> #define rep(i,a,n) for (int i=a;i<n;i++) #define per(i,a,n) for (int i=n-1;i>=a;i--) #define pb push_back #define mp make_pair #define all(x) (x).begin(),(x).end() #define fi first #define se second #define eps 1e-8 #define M_PI 3.141592653589793 typedef long long ll; const ll mod=1000000007; const int inf=99999999; ll powmod(ll a,ll b) {ll res=1;a%=mod;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;} using namespace std; int A[10100],B[10100],dp[10100][16]; int main() { int n,m; while(~scanf("%d %d",&n,&m)) { int tot=n*m; rep(i,0,n) cin>>A[i]; rep(i,0,n) cin>>B[i]; rep(i,0,tot) { A[i]=A[i%n]; B[i]=B[i%n]; } rep(i,0,tot+1) rep(j,0,16) dp[i][j]=inf; dp[1][1]=A[0]; for(int i=1;i<tot;i++) { for(int j=0;j<15;j++) { int k=j+1; dp[i+1][k]=dp[i][j]+A[i]; if(k==15){ k=10;//注意这里有一点和背包问题变形,当15说明卡两张满了,能量槽满了爆0 dp[i+1][k]=min(dp[i+1][k],dp[i][j]+A[i]); } if(j>=5) dp[i+1][j-5]=min(dp[i][j]+B[i],dp[i+1][j-5]); } } int res=inf; for(int i=0;i<15;i++) res=min(res,dp[tot][i]); cout<<res<<endl; } }
在最近散漫写了一个星期基础动态规划后,趁热把这题的转态转移方程推一下,定义dp[i][j]为前i段路此时还有j个能量的最小消耗值。
则分类讨论根据每个j可能由上一个状态中的那个转移过来,分析可得i=0时,一定时使用了加速卡,i+5<15,则可能时使用了加速卡,i=10比较特殊当独讨论,其他都是直接能量+1过来的。
#include <fstream> #include <iostream> #include <string> #include <complex> #include <math.h> #include <set> #include <vector> #include <map> #include <queue> #include <stdio.h> #include <stack> #include <algorithm> #include <list> #include <ctime> #include <memory.h> #include <ctime> #include <assert.h> #define rep(i,a,n) for (int i=a;i<n;i++) #define per(i,a,n) for (int i=n-1;i>=a;i--) #define pb push_back #define mp make_pair #define all(x) (x).begin(),(x).end() #define fi first #define se second #define eps 1e-8 #define M_PI 3.141592653589793 typedef long long ll; const ll mod=1000000007; const int inf=99999999; ll powmod(ll a,ll b) {ll res=1;a%=mod;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;} using namespace std; int A[10100],B[10100],dp[10100][16],dp1[10100][16]; int main() { int n,m; while(~scanf("%d %d",&n,&m)){ int tot=n*m; for(int i=0;i<n;i++) cin>>A[i]; for(int i=0;i<n;i++) cin>>B[i]; for(int i=0;i<tot;i++) A[i]=A[i%n],B[i]=B[i%n]; for(int i=0;i<=tot;i++){ for(int j=0;j<16;j++){ dp[i][j]=inf; } } dp[0][0]=0; for(int i=0;i<tot;i++){ for(int j=0;j<15;j++){ if(j==0) dp[i+1][j]=dp[i][j+5]+B[i]; else if(j==10) dp[i+1][j]=min(dp[i][j-1]+A[i],dp[i][14]+A[i]); else if(j+5<15) dp[i+1][j]=min(dp[i][j-1]+A[i],dp[i][j+5]+B[i]); else dp[i+1][j]=dp[i][j-1]+A[i]; } } int ans=dp[tot][0]; for(int i=0;i<15;i++){ ans=min(ans,dp[tot][i]); } cout<<ans<<endl; } }
还有一个小师傅的非常易懂代码,很值得学习啊!
#include<bits/stdc++.h> using namespace std; const int max_card = 3,max_energy = 5,max_segments = 110,max_laps = 110; const ll INF = 10000000000000; ll dp[max_laps*max_segments][max_card][max_energy]; int with[max_segments],without[max_segments]; void init(){ memset(dp, 0x3f3f3f3f, sizeof(dp)); } void input(const int&l){ for (int i = 0; i<l; i++) { cin>>without[i]; } for (int i = 0; i<l; i++) { cin>>with[i]; } } void solve(const int&l,const int&lap){ init(); input(l); dp[0][0][0] = 0; for (int cur_step = 1; cur_step<=l*lap; cur_step++) { for (int cur_card = 0; cur_card<3; cur_card++) { for (int cur_energy = 0; cur_energy<5; cur_energy++) { if (cur_energy == 0) { if (cur_card == 2) { dp[cur_step][cur_card][cur_energy] = min(dp[cur_step-1][cur_card-1][4],dp[cur_step-1][cur_card][4])+without[(cur_step-1)%l]; }else if(cur_card == 1){ dp[cur_step][cur_card][cur_energy] = min(dp[cur_step-1][cur_card+1][0]+with[(cur_step-1)%l],dp[cur_step-1][0][4]+without[(cur_step-1)%l]); }else{ dp[cur_step][cur_card][cur_energy] = dp[cur_step-1][1][0]+with[(cur_step-1)%l]; } }else{ if (cur_card == 2) { dp[cur_step][cur_card][cur_energy] = dp[cur_step-1][cur_card][cur_energy-1]+without[(cur_step-1)%l]; }else{ dp[cur_step][cur_card][cur_energy] = min(dp[cur_step-1][cur_card+1][cur_energy]+with[(cur_step-1)%l],dp[cur_step-1][cur_card][cur_energy-1]+without[(cur_step-1)%l]); } } } } } ll ans = INF; for (int i = 0; i<5; i++) { for (int j = 0; j<3; j++) { ans = min(ans, dp[l*lap][j][i]); } } cout<<ans<<endl; } int main(){ int l,lap; while(cin>>l>>lap){ solve(l, lap); } return 0; }