一、多种背包问题的组合
二、二维费用背包问题
问题:对于每件物品有两种费用,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