AreYouBusy
AreYouBusy
題意:
給你n個工作集合,給你T的時間去做它們。給你m和s,說明這個工作集合有m件事可以做,它們是s類的工作集合(s=0,1,2,s=0說明這m件事中最少得做一件,s=1說明這m件事中最多只能做一件,s=2說明這m件事你可以做也可以不做)。再給你ci和gi代表你做這件事要用ci的時間,能獲得gi的快樂值。求在T的時間內你能獲得的最大快樂值。
題解:
我們設dp[i][j]表示處理完前i組工作集,所用時間小于j的快樂值
dp[i]表示的是第i組的結果,每組相對獨立,
所以對于每一組情況,我們就可以將dp看作是一維數組,只考慮第二維j,考慮第一維僅為需要繼承狀態時
我們分析三種集合:
轉移方程:
dp[i][j]表示不選這個工作
dp[i][j-w[x]]+p[x]:表示選擇當前工作,且不是第一次取(為什么這個能保證不是第一次取?因為我們一開始將dp[i][…]賦值為負無窮,如果dp[i][j-w[x]]沒被選過就還是負無窮,則整個式子取最大就跟他無關,如果被選過,則dp[i][j-w[x]]為正數)
dp[i-1][j-w[x]]+p[x]:第一次在本組中選物品,由于dp初始化為負無窮,所以狀態的轉移只能從上一組的結果中得知,這樣可以保證得到全局最優解
這樣,當有一組無法完成時,最后的答案就是負無窮
為了保證全局最優解,dp[i][j]繼承上一組的狀態
第一次選的話,和第一種集合的情況一樣
為了保證全局最優解,dp[i][j]繼承上一組的狀態
這里的dp是被壓縮了一維的,這里的dp[][j]中的j等于01背包的一維數組dp[j],
dp[i][]中的i只是表示第i組的情況
代碼:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm>using namespace std;const int INF=0x3f3f3f3f;int n,m,sum; int w[110],p[110]; int dp[110][110];int main(){//freopen("input.txt","r",stdin);while(~scanf("%d%d",&n,&sum)){memset(dp,0,sizeof(dp));int i,j,k,g;for(i=1;i<=n;i++){scanf("%d%d",&m,&g);for(k=1;k<=m;k++)scanf("%d%d",&w[k],&p[k]);if(g==0){//至少選一個 for(j=0;j<=sum;j++) //當前組初始化dp[i][j]=-INF;for(k=1;k<=m;k++)for(j=sum;j>=w[k];j--)dp[i][j]=max(dp[i][j],max(dp[i][j-w[k]]+p[k],dp[i-1][j-w[k]]+p[k]));}else if(g==1){//最多選一個 for(j=0;j<=sum;j++) //當前組初始化dp[i][j]=dp[i-1][j];for(k=1;k<=m;k++)for(j=sum;j>=w[k];j--)dp[i][j]=max(dp[i][j],dp[i-1][j-w[k]]+p[k]); //dp[i-1][j-w[k]]//j-w[k]<j}else if(g==2){//自由選擇 for(j=0;j<=sum;j++) //當前組初始化dp[i][j]=dp[i-1][j];for(k=1;k<=m;k++)for(j=sum;j>=w[k];j--)dp[i][j]=max(dp[i][j],dp[i][j-w[k]]+p[k]);}}dp[n][sum]=max(dp[n][sum],-1); //沒有完成任務的值都為負的,做輸出調整,輸出-1printf("%d\n",dp[n][sum]);}return 0; }總結
以上是生活随笔為你收集整理的AreYouBusy的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 杉寄生的功效与作用、禁忌和食用方法
- 下一篇: 背包模型题目集合