 /**//*
題意:有錢w,給出n種選擇,每種選擇有m[i]個物品,但必須先買盒子,價格p[i]
然后給出每種選擇的一些物品的價格還有價值 求取得最大值

一開始我想用兩個數組,一個記錄已經買了box的,一個還沒的
這樣子轉移時有兩種
但注意有0的數據,被題目蒙了 .

下面的是龍教主的做法,比較簡潔
由于要買box,就先更新一下以前的數組,使得dp[j+p[i]] = _dp[j]
_dp[]最后要更新下,保存最優值
背包變形加狀態做,方便點?hdu 3236也是加狀態做
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

 inline int max(int a,int b) {return a>b?a:b;}

const int MAXN = 100010;
const int INF = 1000000000;

int dp[MAXN],_dp[MAXN];//within n , without n
int p[51],m[51],c[51][11],v[51][11];

int main()
  {
//freopen("in","r",stdin);
int n,w;
while(~scanf("%d%d",&n,&w))
 {
for(int i=1;i<=n;i++)
 {
scanf("%d%d",&p[i],&m[i]);
for(int j=1;j<=m[i];j++)
scanf("%d%d",&c[i][j],&v[i][j]);
}
for(int j=0;j<=w;j++)dp[j] = _dp[j] = 0;
for(int i=1;i<=n;i++)
 {
for(int j=0;j+p[i]<=w;j++)dp[j+p[i]] = _dp[j];//由于需要先買box,要先更新可以枚舉的起點
for(int k=1;k<=m[i];k++)
for(int j=w;j>=p[i]+c[i][k];j--)
dp[j] = max(dp[j],dp[j-c[i][k]]+v[i][k]);
for(int j=p[i];j<=w;j++)//前i次的最優值
_dp[j] = max(_dp[j],dp[j]);
}
int ans = 0;
for(int j=0;j<=w;j++)
ans = max(ans,_dp[j]);
printf("%d\n",ans);
}
return 0;
}

 /**//*

之前的做法跟上面的類似
不過轉移時分兩種: 從沒有box的,從有box的轉移過來
for(int j=0;j<=w;j++)
{
dp[now][j] = -INF;
_dp[now][j] = max(dp[pre][j],_dp[pre][j]);
}
for(int k=1;k<=m[i];k++)
for(int j=w;j>=p[i]+c[i][k];j--)
{
//注意有0的數據,所以要按照下面的順序
//反過來的話,會錯,因為dp[now][j-c[i][k]]可能被更新過了,不是之前的值了
dp[now][j] = max(dp[now][j],dp[now][j-c[i][k]]+v[i][k]);
dp[now][j] = max(dp[now][j],_dp[now][j-p[i]-c[i][k]]+v[i][k]);
}
*/
|
|
常用鏈接
隨筆分類
Links
搜索
最新評論

|
|