hdu1494(好题 DP%)

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





你可能感兴趣的:(hdu1494(好题 DP%))