Comet OJ - Contest #11 B題 usiness

###題目連接###前端

題目大意:一開始手上有 0 個節點,有 n 天抉擇,m 種方案,在天天中能夠選擇任意種方案、任意次得花費 x 個節點(手上的節點數不能爲負),使得在 n 天結束後,得到 y 個節點。ios

其次,在天天結束後,會根據本身手上所具備的節點數來得到一些節點,設當天結束後所擁有 x 個節點,那麼將得到 f(x) 個節點。優化

 

分析:spa

一、將全過程分爲 n 天,天天開始有必定的節點數,而後 DP 求得花費後的最大價值(這個最大價值指的是,n 天結束後僅返還得到的最大節點數)。故設 dp[i][j] 表示在第 i 天花費操做完後,所能在最後一天返還節點數的最大值。code

二、很顯然這是一個徹底揹包問題。在 DP 處理天天話費節點以前,須要更新當天最開始所擁有的節點數所表明的 價值 (即結束返還的總節點數)。而當天一開始的節點數由上一天末尾所持有的節點數 x  + 上一天結束後得到的節點數 f(x) 。blog

故枚舉上一天結束後所持有的節點數 j ,則有: dp[i][j+f[j]]=max(dp[i][j+f[j]] , dp[i-1][j])get

 

直接枚舉物品數:string

 

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int n,m,k;
int s[1008];
int dp[108][2008];
struct Good{
    int a,b;
}A[108];
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=0;i<=k;i++) scanf("%d",&s[i]);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&A[i].a,&A[i].b);
    }
    memset(dp,0xc0c0c0c0,sizeof(dp));
    dp[1][0]=0;
    for(int i=2;i<=n;i++){
        for(int j=0;j<=k;j++){
            dp[i][j+s[j]]=max(dp[i][j+s[j]],dp[i-1][j]);
        }
        for(int w=1;w<=m;w++){
            for(int j=A[w].a;j<=2000;j++){
                for(int e=1;e<=j/A[w].a;e++){
                    dp[i][j-e*A[w].a]=max(dp[i][j-e*A[w].a],dp[i][j]+e*A[w].b);
                }
            }
        }
    }
    int ans=0;
    for(int i=0;i<=2000;i++){
        ans=max(ans,dp[n][i]+i+s[i]);
    }
    printf("%d\n",ans);
}

 

 

 優化要注意的是:因爲這裏的 dp 轉移方程的方向是從末端向前轉移過來的,而徹底揹包優化掉一個循環的原理是要用到在本層以前的物品狀態,故枚舉方向對應的也須要從末端向前端。it

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int n,m,k;
int s[1008];
int dp[108][2008];
struct Good{
    int a,b;
}A[108];
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=0;i<=k;i++) scanf("%d",&s[i]);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&A[i].a,&A[i].b);
    }
    memset(dp,0xc0c0c0c0,sizeof(dp));
    dp[1][0]=0;
    for(int i=2;i<=n;i++){
        for(int j=0;j<=k;j++){
            dp[i][j+s[j]]=max(dp[i][j+s[j]],dp[i-1][j]);
        }
        for(int w=1;w<=m;w++){
            for(int j=2000;j>=A[w].a;j--){
                dp[i][j-A[w].a]=max(dp[i][j-A[w].a],dp[i][j]+A[w].b);
            }
        }
    }
    int ans=0;
    for(int i=0;i<=2000;i++){
        ans=max(ans,dp[n][i]+i+s[i]);
    }
    printf("%d\n",ans);
}
相關文章
相關標籤/搜索