hdu-3449 Consumer(典型的依赖背包)

Consumer

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/65536 K (Java/Others)
Total Submission(s): 1498    Accepted Submission(s): 787


Problem Description
FJ is going to do some shopping, and before that, he needs some boxes to carry the different kinds of stuff he is going to buy. Each box is assigned to carry some specific kinds of stuff (that is to say, if he is going to buy one of these stuff, he has to buy the box beforehand). Each kind of stuff has its own value. Now FJ only has an amount of W dollars for shopping, he intends to get the highest value with the money.
 

Input
The first line will contain two integers, n (the number of boxes 1 <= n <= 50), w (the amount of money FJ has, 1 <= w <= 100000) Then n lines follow. Each line contains the following number pi (the price of the ith box 1<=pi<=1000), mi (1<=mi<=10 the number goods ith box can carry), and mi pairs of numbers, the price cj (1<=cj<=100), the value vj(1<=vj<=1000000)
 

Output
For each test case, output the maximum value FJ can get
 

Sample Input
   
   
3 800 300 2 30 50 25 80 600 1 50 130 400 3 40 70 30 40 35 60
 

Sample Output
   
   
210
 

此类背包典型的关系是若想选b,你必须先选a,从而产生了一层依赖关系,然后给你一定限量的总钱数,让你买最大价值的东西

就让我们从hdu 3449 来搞定这类最简单的依赖背包吧

有很多个箱子,想买箱子中的物品必须先买下箱子,典型的依赖背包

dp[i][j]代表前i个箱子花费j的钱能获得的最大价值,则可以想到每次在对一个箱子进行dp更新状态时都应该利用前面的结果来更新

#include<cstdio>
#include<cstring>
int dp[60][100010];
int tmp[100010];
int max(int a,int b){return a>b?a:b;}
int main()
{
int n,tot,i,j,k;
while(scanf("%d%d",&n,&tot)!=EOF)
{
int p,m,w,v;
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
{
memset(tmp,-1,sizeof(tmp));
scanf("%d%d",&p,&m);
for(j=p;j<=tot;j++)
tmp[j]=dp[i-1][j-p];//继承上一层的结果
for(j=1;j<=m;j++)
{
scanf("%d%d",&w,&v);
for(k=tot;k>=w;k--)
{
if(tmp[k-w]!=-1)
tmp[k]=max(tmp[k],tmp[k-w]+v);//01背包部分
}
}
for(j=tot;j>=0;j--)//如果能更新上一层的状态,就更新。
dp[i][j]=max(tmp[j],dp[i-1][j]);
}
printf("%d\n",dp[n][tot]);
}
return 0;
}

也可以不用tmp数组

#include<cstdio>
#include<cstring>
int dp[60][100010];
int max(int a,int b){return a>b?a:b;}
int main()
{
int n,tot,i,j,k;
while(scanf("%d%d",&n,&tot)!=EOF)
{
int p,m,w,v;
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
{
scanf("%d%d",&p,&m);
for(j=0;j<p;j++) dp[i][j]=-1;
for(j=p;j<=tot;j++) dp[i][j]=dp[i-1][j-p];//继承上一层的结果,j-p是因为一定要买箱子
for(j=1;j<=m;j++)
{
scanf("%d%d",&w,&v);
for(k=tot;k>=w;k--)
{
if(dp[i][k-w]!=-1)
dp[i][k]=max(dp[i][k],dp[i][k-w]+v);//01背包部分
}
}
for(j=tot;j>=0;j--)//如果能更新上一层的状态,就更新。
dp[i][j]=max(dp[i][j],dp[i-1][j]);
}
printf("%d\n",dp[n][tot]);
}
return 0;
}

还可以用一维的

dp[i]代表花i的钱能得到的最大价值

#include<stdio.h>
#include<string.h>
int dp[100010];
int tmp[100010];
int max(int a,int b){return a>b?a:b;}
int main()
{
int n,tot,p,w,v,m,i,j,k;
while(scanf("%d%d",&n,&tot)!=EOF)
{
memset(dp,0,sizeof(dp));
for(i=0;i<n;i++)
{
scanf("%d%d",&p,&m);
memcpy(tmp,dp,sizeof(dp));//继承前面的
for(j=0;j<m;j++)
{
scanf("%d%d",&w,&v);
for(k=tot-p;k>=w;k--)//按照背包九讲的说法,先将附件进行1次01背包
tmp[k]=max(tmp[k],tmp[k-w]+v);
}
for(j=p;j<=tot;j++)//更新能更新的
dp[j]=max(dp[j],tmp[j-p]);
}
printf("%d\n",dp[tot]);
}
return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值