0/背包问题:
一个旅行者有一个最多能用m公斤的背包,现在有n件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为C1,C2,...,Cn.若每种物品只有一件求旅行者能获得最大总价值。
输入
第1行:两个整数,M(背包容量,M<=200)和N(物品数量,N<=30);
第2..N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。
输出
仅一行,一个数,表示最大总价值。
样例输入 Copy
10 4
2 1
3 3
4 5
7 9
样例输出 Copy
12
#include<bits/stdc++.h> #include<cstdio> #include<cmath> #include<algorithm> #include<iostream> using namespace std; const int maxn=50; const int maxw=300; struct Name{ int w; int value; }c[maxn]; int dp[maxn][maxw]; int main(){ int n,W; scanf("%d%d",&W,&n); for(int i=1;i<=n;i++){ cin >> c[i].w >> c[i].value; } memset(dp,0,sizeof(dp)); //定义边界 for(int i=1;i<=n;i++){ for(int j=0;j<=W;j++){ if(c[i].w>j) dp[i][j] = dp[i-1][j]; else { dp[i][j]=max(dp[i-1][j],dp[i-1][j-c[i].w]+c[i].value); } } } printf("%d\n",dp[n][W]); return 0; }
完全背包问题:
设有n种物品,每种物品有一个重量及一个价值。但每种物品的数量是无限的,同时有一个背包,最大载重量为M,今从n种物品中选取若干件(同一种物品可以多次选取),使其重量的和小于等于M,而价值的和为最大。
输入
第一行:两个整数,M(背包容量,M<=200)和N(物品数量,N<=30);
第2..N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。
输出
仅一行,一个数,表示最大总价值。
样例输入 Copy
10 4
2 1
3 3
4 5
7 9
样例输出 Copy
max=12
#include<bits/stdc++.h> #include<cstdio> #include<cmath> #include<algorithm> #include<iostream> using namespace std; const int maxm = 201, maxn = 31; int m, n; int w[maxn], c[maxn]; int f[maxn][maxm]; int main() { scanf("%d%d",&m, &n); //背包容量m和物品数量n for (int i = 1; i <= n; i++) scanf("%d%d",&w[i],&c[i]); //每个物品的重量和价值 for (int i = 1; i <= n; i++) //f[i][v]表示前i件物品,总重量不超过v的最优价值 for (int v = 1; v <= m; v++) if (v < w[i]) f[i][v] = f[i-1][v]; else f[i][v] = max(f[i-1][v] , f[i][v-w[i]]+c[i]); printf("max=%d",f[n][m]); // f[n][m]为最优解 return 0; }
多重背包问题:
为了庆贺班级在校运动会上取得全校第一名成绩,班主任决定开一场庆功会,为此拨款购买奖品犒劳运动
员。期望拨款金额能购买最大价值的奖品,可以补充他们的精力和体力。
输入
第一行二个数n(n<=500),m(m<=6000),其中n代表希望购买的奖品的种数,m表示拨款金额。
接下来n行,每行3个数,v、w、s,分别表示第I种奖品的价格、价值(价格与价值是不同的概念)和购买的
数量(买0件到s件均可),其中v<=100,w<=1000,s<=10。
输出
第一行:一个数,表示此次购买能获得的最大的价值(注意!不是价格)。
样例输入 Copy
5 1000
80 20 4
40 50 9
30 50 7
40 30 6
20 20 1
样例输出 Copy
1040
#include<bits/stdc++.h> #include<cstdio> #include<cmath> #include<algorithm> #include<iostream> using namespace std; int v[6002], w[6002], s[6002]; int f[6002]; int n, m; int main() { scanf("%d%d",&n,&m); for (int i = 1; i <= n; i++) scanf("%d%d%d",&v[i],&w[i],&s[i]); //输入价格 价值 件数 for (int i = 1; i <= n; i++) //物品种类 for (int j = m; j >= 0; j--) //总金额 for (int k = 0; k <= s[i]; k++){ //控制件数 有s[i]+1种取法:0,1,2,3…… if (j - k*v[i] < 0) break; ////若超过金额就循环下一个金额。 f[j] = max(f[j],f[j-k*v[i]]+k*w[i]); } printf("%d",f[m]); return 0; }
混合背包问题:
一个旅行者有一个最多能用V公斤的背包,现在有n件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为C1,C2,...,Cn。有的物品只可以取一次(01背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包)。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
输入
第一行:二个整数,V(背包容量,V<=200),N(物品数量,N<=30);
第2..N+1行:每行三个整数Wi,Ci,Pi,前两个整数分别表示每个物品的重量,价值,第三个整数若为0,则说
明此物品可以购买无数件,若为其他数字,则为此物品可购买的最多件数(Pi)。
输出
仅一行,一个数,表示最大总价值。
样例输入 Copy
10 3
2 1 0
3 3 1
4 5 4
样例输出 Copy
11
#include<bits/stdc++.h> #include<cstdio> #include<cmath> #include<algorithm> #include<iostream> using namespace std; int w[205],c[205],p[205]; int f[205]; int main() { int v,n; scanf("%d%d",&v,&n); for(int i=1;i<=n;i++) scanf("%d%d%d",&w[i],&c[i],&p[i]); for(int i=1;i<=n;i++){ if(p[i] == 0){ for(int j=w[i];j<=v;j++){ //完全背包 f[j]=max(f[j],f[j-w[i]]+c[i]); } } else{ for(int j=1;j<=p[i];j++){ //01背包及购买p[i]件 for(int k=v;k>=w[i];k--) f[k]=max(f[k],f[k-w[i]]+c[i]); } } } printf("%d\n",f[v]); }
二维费用的背包问题:
潜水员为了潜水要使用特殊的装备。他有一个带2种气体的气缸:一个为氧气,一个为氮气。让潜水员下潜的深度需要各种的数量的氧和氮。潜水员有一定数量的气缸。每个气缸都有重量和气体容量。潜水员为了完成他的工作需要特定数量的氧和氮。他完成工作所需气缸的总重的最低限度的是多少?
例如:潜水员有5个气缸。每行三个数字为:氧,氮的(升)量和气缸的重量:
3 36 120
10 25 129
5 50 250
1 45 130
4 20 119
如果潜水员需要5升的氧和60升的氮则总重最小为249(1,2或者4,5号气缸)。
你的任务就是计算潜水员为了完成他的工作需要的气缸的重量的最低值。
输入
第一行有2整数m,n(1<=m<=21,1<=n<=79)。它们表示氧,氮各自需要的量。
第二行为整数k(1<=n<=1000)表示气缸的个数。
此后的k行,每行包括ai,bi,ci(1<=ai<=21,1<=bi<=79,1<=ci<=800)3整数。这些各自是:第i个气
缸里的氧和氮的容量及汽缸重量。
输出
仅一行包含一个整数,为潜水员完成工作所需的气缸的重量总和的最低值。
样例输入 Copy
5 5
9
1 1 12
3 1 52
1 3 71
2 1 33
3 2 86
2 3 91
2 2 43
3 3 113
1 2 28
样例输出 Copy
104
#include<cstdio> #include<cstring>//初始化memset要用到 using namespace std; int v, u, k; int a[1001], b[1001], c[1001]; int f[101][101]; int main(){ memset(f,127,sizeof(f)); //初始化为一个很大的正整数 f[0][0] = 0; scanf("%d%d%d",&v,&u,&k); for (int i = 1; i <= k; i++) scanf("%d%d%d",&a[i],&b[i],&c[i]); for (int i = 1; i <= k; i++) for (int j = v; j >= 0; j--) for (int l = u; l >= 0; l--){ int t1 = j+ a[i],t2 = l + b[i]; if (t1 > v) t1 = v; //若氮、氧含量超过需求,可直接用需求量代换 if (t2> u) t2 = u; //不影响最优解 if (f[t1][t2] > f[j][l] + c[i]) f[t1][t2] = f[j][l] + c[i]; } printf("%d",f[v][u]); return 0; }
分组背包问题:
一个旅行者有一个最多能用V公斤的背包,现在有n件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为C1,C2,...,Cn。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
输入
第1行:三个整数,V(背包容量,V<=200),N(物品数量,N<=30)和T(最大组号,T<=10);
第2..N+1行:每行三个整数Wi,Ci,P,表示每个物品的重量,价值,所属组号。
输出
仅一行,一个数,表示最大总价值。
样例输入 Copy
10 6 3
2 1 1
3 3 1
4 8 2
6 9 2
2 8 3
3 9 3
样例输出 Copy
20
#include<cstdio> using namespace std; int v, n, t; int w[31], c[31]; int a[11][32], f[201]; int main(){ scanf("%d%d%d",&v,&n,&t); for (int i = 1; i <= n; i++){ int p; scanf("%d%d%d",&w[i],&c[i],&p); a[p][++a[p][0]] = i; } for (int k = 1; k <= t; k++) for (int j = v; j >= 0; j--) for (int i = 1; i <= a[k][0]; i++) if (j >= w[a[k][i]]){ int tmp = a[k][i]; if (f[j] < f[j-w[tmp]]+c[tmp]) f[j] = f[j-w[tmp]]+c[tmp]; } printf("%d",f[v]); return 0; }