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;
}