背包问题二

一、多种背包问题的组合

 二、二维费用背包问题

问题:对于每件物品有两种费用,ci和di,每件物品的价值是vi,背包的对两种费用的限度分别是V和U,

求不超过V和U的情况下可获得的最大价值。

状态准一方程:f(i,j,k)=max{f(i-1,j,k),f(i-1,j-ci,k-di)+vi};

#include<bits/stdc++.h>
using namespace std;
int c1[1200],d1[1200],v[1200],dp[1200][1200];
int main(void)
{
	int n,i,j,k;
	int V,U;//V表示限度1,限度2
	memset(c1,0,sizeof(c1));
	memset(d1,0,sizeof(d1));
	memset(v,0,sizeof(v));
	memset(dp,0,sizeof(dp));
	scanf("%d",&n);
	scanf("%d%d",&V,&U);
	for(i=1;i<=n;i++)
	scanf("%d%d%d",&c1[i],&d1[i],&v[i]);
	for(i=1;i<=n;i++)
	{
		for(j=V;j>=c1[i];j--)
		{
			for(k=U;k>=d1[i];k--)
			{
				if(dp[j][k]<dp[j-c1[i]][k-d1[i]]+v[i])
				dp[j][k]=dp[j-c1[i]][k-d[i]]+v[i];
			}
		}
	}
	printf("%d\n",dp[V][U]);
	return 0;
}

/*测试数据: 
5
5 60
3 36 120
10 25 129
5 50 250
1 45 130
4 20 119
*/

参考文章:http://www.cnblogs.com/justPassBy/p/4279674.html

参考文章:https://www.cnblogs.com/z360/p/6365994.html

参考文章:https://blog.csdn.net/baidu_23955875/article/details/47068655

 

三、分组背包问题

问题:有一个体积为V的背包,有n件物体,每件物体的体积是c[i],价值是v[i],现在有k组物体,每组物体只能选一个,

它们之间相互冲突,求背包获得的最大价值。

状态转移方程:f(k,vi)=max{f(k-1,V),f(k-1,V-ci)+v[i]};(0<=i<=k);

下面举个例子说明一下(hdu-1712)

ACboy needs your help

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 8554    Accepted Submission(s): 4720


 

Problem Description

ACboy has N courses this term, and he plans to spend at most M days on study.Of course,the profit he will gain from different course depending on the days he spend on it.How to arrange the M days for the N courses to maximize the profit?

 

 

Input

The input consists of multiple data sets. A data set starts with a line containing two positive integers N and M, N is the number of courses, M is the days ACboy has.
Next follow a matrix A[i][j], (1<=i<=N<=100,1<=j<=M<=100).A[i][j] indicates if ACboy spend j days on ith course he will get profit of value A[i][j].
N = 0 and M = 0 ends the input.

 

 

Output

For each data set, your program should output a line which contains the number of the max profit ACboy will gain.

 

 

Sample Input

 

2 2 1 2 1 3 2 2 2 1 2 1 2 3 3 2 1 3 2 1 0 0

 

 

Sample Output

 

3 4 6

 

 

Source

HDU 2007-Spring Programming Contest

 

 

Recommend

lcy   |   We have carefully selected several similar problems for you:  2159 1561 2602 3033 2955 

 

 

Statistic | Submit | Discuss | Note

 

#include<bits/stdc++.h>
using namespace std;
int a[105][105],dp[105];
int main(void)
{
	int n,m;
	int i,j,k;
	while(~scanf("%d%d",&n,&m))
	{
		if(m==0&&n==0) break;
		memset(a,0,sizeof(a));
		memset(dp,0,sizeof(dp)); 
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=m;j++)
			scanf("%d",&a[i][j]);
		}
		for(i=1;i<=n;i++) //从1到n寻找 
		{
			for(k=m;k>=0;k--) //先设定背包体积,寻找合适的背包体积 
			{
				for(j=1;j<=m;j++) //在每一类中寻找合适的背包 
				{
					if(k-j>=0) //防止数组越界,防止背包体积为负数
					{
						dp[k]=max(dp[k],dp[k-j]+a[i][j]); //找到价值最大的背包 
					}
				}
			}
		}
		printf("%d\n",dp[m]);
	}
	return 0;
} 

参考文章:https://www.cnblogs.com/xuejianye/p/5426377.html

 

四、有依赖的背包问题

 

 

问题引入:金明的预算问题 

【问题描述】

金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。今天一早,金明就开始做预算了,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:

主件附件
电脑打印机,扫描仪
书柜图书
书桌台灯,文具
工作椅

如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有0个、1个或2个附件。附件不再有从属于自己的附件。金明想买的东西很多,肯定会超过妈妈限定的N元。于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。他还从因特网上查到了每件物品的价格(都是10元的整数倍)。他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。

设第j件物品的价格为vjvj,重要度为wjwj,共选中了k件物品,编号依次为j1,j2,……,jkj1,j2,……,jk,则所求的总和为:

 

vj1∗wj1+vj2∗wj2+…+vjk∗wjkvj1∗wj1+vj2∗wj2+…+vjk∗wjk

 

请你帮助金明设计一个满足要求的购物单。

【输入文件】

输入文件budget.in 的第1行,为两个正整数,用一个空格隔开:N m 
(其中N(<32000)表示总钱数,m(<60)为希望购买物品的个数。) 
从第2行到第m+1行,第j行给出了编号为j-1的物品的基本数据,每行有3个非负整数 v p q(其中v表示该物品的价格(v<10000),p表示该物品的重要度(1~5),q表示该物品是主件还是附件。如果q=0,表示该物品为主件,如果q>0,表示该物品为附件,q是所属主件的编号)

【输出文件】

输出文件budget.out只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值(<200000)。

【输入样例】

1000 5

800 2 0

400 5 1

300 5 1

400 3 0

500 2 0

【输出样例】

2200

 

思路:是01背包的变形形式;

分为5种情况

1、什么都不要

2、只要主体

3、要主体和附件1

4、要主体和附件2

5、要主体和附件1,附件2.

还要注意输入时的主件还是附件区分一下。

#include<bits/stdc++.h>
using namespace std;

int v[65][3],w[65][3]; //分别表示主件价值v和附件价值w;
int dp[65][32010][5]; //分别考虑m件数,n总体积,p重要度 
int main(void)
{
	int n,m;
	int i,j,k;
	int vi,pi,qi;
	memset(v,0,sizeof(v));
	memset(w,0,sizeof(w));
	memset(dp,0,sizeof(dp));
	scanf("%d%d",&m,&n);
	for(i=1;i<=n;i++)
	{
		scanf("%d%d%d",&vi,&pi,&qi);
		if(qi) //是主件 
		{
			if(w[qi][1])
			{
				v[qi][2]=vi*pi;
				w[qi][2]=vi;
			}
			else 
			{
				v[qi][1]=vi*pi;
				w[qi][1]=vi;
			}
		}
		else  //是附件 
		{
			v[i][0]=vi*pi;
			w[i][0]=vi;
		} 
	}
	int maxn=-1;
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			for(k=0;k<5;k++)
			{
				dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][k]); //什么也不要 
				if(j-w[i][0]>=0) //只要主件 
				dp[i][j][1]=max(dp[i][j][1],dp[i-1][j-w[i][0]][k]+v[i][0]); 
				if(j-w[i][0]-w[i][1]>=0) //只要主件和附件1 
				dp[i][j][2]=max(dp[i][j][2],dp[i-1][j-w[i][0]-w[i][1]][k]+v[i][0]+v[i][1]);
				if(j-w[i][0]-w[i][2]>=0) //只要主件和附件2 
				dp[i][j][3]=max(dp[i][j][3],dp[i-1][j-w[i][0]-w[i][2]][k]+v[i][0]+v[i][2]);
				if(j-w[i][0]-w[i][1]-w[i][2]>=0) //只要主件和附件1,附件2 
				dp[i][j][4]=max(dp[i][j][4],dp[i-1][j-w[i][0]-w[i][1]-w[i][2]][k]+v[i][0]+v[i][1]+v[i][2]);
			}
			for(k=0;k<5;k++)
			maxn=max(maxn,dp[i][j][k]);
		}
	}
	printf("%d\n",maxn);
	return 0;
}

参考文章:https://blog.csdn.net/qq_22141519/article/details/47186989

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值