目录
介绍:
一、01背包
题目描述
输入描述:
输出描述:
代码:
二、完全背包
题目描述
输入描述:
输出描述:
代码:
三、多重背包
题目描述
输入描述:
输出描述:
代码:
四、背包问题
题目描述
输入描述:
输出描述:
代码:
五、变1
代码:
六、变2
代码:
七、变3
代码:
介绍:
背包问题是一个经典的组合优化问题,它的目标是在给定的一组物品中选择一些物品放入背包中,使得这些物品的总价值最大化,同时限制背包的容量。
背包问题有多种变体,其中最常见的是0-1背包问题。在0-1背包问题中,每个物品要么完整地放入背包中,要么不放入,不存在放入一部分的情况。每个物品都有对应的价值和重量,背包有一个固定的容量限制。问题在于选择哪些物品放入背包中,使得总价值最大化,同时不超过背包的容量。
解决背包问题的方法包括动态规划、贪心法和回溯法。动态规划是最常用的解决方法,其基本思想是将问题划分为子问题,并使用一个二维数组来保存子问题的最优解。贪心法则是每次选择当前最有利的物品放入背包,但不一定能得到最优解。回溯法则是穷举所有可能的解,并逐步剪枝,但在处理大规模问题时效率较低。
背包问题具有广泛的应用,例如资源分配、排课问题、投资组合优化等。
一、01背包
题目描述
你有一个背包,最多能容纳的体积是V。
现在有n个物品,第i个物品的体积为v ,价值为w。
(1)求这个背包至多能装多大价值的物品?
(2)若背包恰好装满,求至多能装多大价值的物品?
输入描述:
第一行两个整数n和V,表示物品个数和背包体积。
接下来n行,每行两个数v和w,表示第i个物品的体积和价值。
1≤n,V,vi,wi≤10001 \le n,V,v_i,w_i \le 10001≤n,V,vi,wi≤1000
输出描述:
输出有两行,第一行输出第一问的答案,第二行输出第二问的答案,如果无解请输出0。
代码:
#include<iostream>
#include<cstring>
using namespace std;
int main()
{int n, v;cin >> n >> v;int a[1005],b[1005];int f[1005][1005];//表示第i个物品装满j体积memset(f, -0x3f, sizeof(f));for (int i = 1; i <= n; i++)cin >> a[i] >> b[i];int ans = 0;f[0][0]=0;//0个物体可以装满0体积for(int i=1;i<=n;i++)for (int j = 0; j <= v; j++){if(a[i]<=j)//体积大于该物体体积,才可以装物品f[i][j] = max(f[i - 1][j], f[i - 1][j - a[i]] + b[i]);else//不装该物体f[i][j]=f[i-1][j];if (ans < f[i][j])//求最大价值ans = f[i][j];}cout << ans << endl;if(f[n][v]>0)cout << f[n][v] << endl;elsecout<<0;
}
二、完全背包
题目描述
你有一个背包,最多能容纳的体积是V。
现在有n种物品,每种物品有任意多个,第i种物品的体积为vi ,价值为wi。
(1)求这个背包至多能装多大价值的物品?
(2)若背包恰好装满,求至多能装多大价值的物品?
输入描述:
第一行两个整数n和V,表示物品个数和背包体积。
接下来n行,每行两个数v和w,表示第i种物品的体积和价值。
1≤n,V≤10001 \le n, V \le 10001≤n,V≤1000
输出描述:
输出有两行,第一行输出第一问的答案,第二行输出第二问的答案,如果无解请输出0。
代码:
#include<iostream>
#include<cstring>
using namespace std;
int main()
{long long n, V;cin >> n >> V;long long dp1[1010], dp2[1010];memset(dp1, 0, sizeof(dp1)), memset(dp2, 0, sizeof(dp2));for (int i = 1; i <= n; i++){long long v, w;cin >> v >> w;for (int j = 0; j <= V; j++){if (j >= v){dp1[j] = max(dp1[j], dp1[j - v] + w);if (j % v == 0 || dp2[j-v] != 0) //该体积为该物体体积的倍数或者该体积减去物体体积不为0dp2[j] = max(dp2[j], dp2[j - v] + w);//塞这个物品,原先该体积的价值和减去该体积的价值加塞下该物品的价值谁大}}}cout << dp1[V] << endl;cout << dp2[V] << endl;
}
三、多重背包
题目描述
有 n 种物品,第 i 种物品有 x 个,每一个物品重量为 w ,价值为 v,现有一个承重能力为 T 的背包,在不超过承重能力的情况下,背包种最多能装多少价值的物品。
输入描述:
第一行输入两个整数 n,T(1≤n,T≤100)n,T(1\le n,T \le 100)n,T(1≤n,T≤100) ,代表物品种数和背包承重能力。
接下来 nnn 行,每行三个整数 xi,wi,vi(1≤xi,wi≤20,1≤vi≤200)x_i,w_i,v_i(1\le x_i,w_i\le 20,1\le v_i \le 200)xi,wi,vi(1≤xi,wi≤20,1≤vi≤200) 描述一个物品,分别代表物品的个数、物品的重量、物品的价值。
输出描述:
输出一行一个整数,表示在不超过承重能力的情况下,背包物品的最大价值。
代码:
#include<iostream>
using namespace std;
int main()
{int n, t;cin >> n >> t;int f[105][105];//表示第i个物品装j体积for (int i = 1; i <= n; i++){int x, w, v;cin >> x >> w >> v;for (int j = 0; j <= t; j++){for (int k = 0; k <= x; k++)//表示放k个该物品if(j>=k*w)//要该体积大于k个物品体积才能放那么多个物品f[i][j] = max(f[i][j], f[i - 1][j - k * w] + k*v);}}cout << f[n][t];
}
四、背包问题
题目描述
牛妹家里有n个物品,第i个物品体积为v,价值为w。牛妹有一个容积无穷大的背包,背包可以装任意多的物品,没有限制。
牛妹要去深山中度假,为了在旁人眼中显得自己准备得很充分,牛妹想在背包中装入总体积不小于V的一些物品。如果装入的物品过于贵重,路上如果遇到强盗、劫匪、山贼等就很亏。所以牛妹想知道总体积不小于V的前提下,物品的总价值最小是多少。输入描述:
第一行两个整数n,V\mathit n,Vn,V,表示物品的数量和总体积需求。接下来n\mathit nn行,每行两个整数vi,wiv_i,w_ivi,wi,表示第i\mathit ii种物品的体积和价值。保证所有物品总体积不小于V\mathit VV。
1≤n≤200,1≤V≤106,1≤vi≤106,1≤wi≤2001 \leq n \leq 200, 1 \leq V \leq 10^6, 1 \leq v_i \leq 10^6, 1 \leq w_i \leq 2001≤n≤200,1≤V≤106,1≤vi≤106,1≤wi≤200。保证所有物品总体积不小于V\mathit VV。
输出描述:
输出一个整数,表示答案。
代码:
#include<iostream>
using namespace std;
int v[1000100], w[1000100];
int f[1000100];//j价值可以装的最大体积
int main()
{int n,V;long long sum = 0;cin >> n >> V;for (int i = 1; i <= n; i++){cin >> v[i] >> w[i];sum += w[i];//总价值}for (int i = 1; i <= n; i++){for (int j = sum; j >= w[i]; j--)f[j] = max(f[j], f[j - w[i]] + v[i]);}for (int i = 1; i <= sum; i++)if (f[i] >= V)//找到大于等于V体积的最小价值{cout << i << endl;break;}
}
五、变1
代码:
#include<iostream>
using namespace std;
int main()
{int n, m;cin >> n >> m;int v[30], p[30];for (int i = 1; i <= m; i++){cin >> v[i] >> p[i];}long long dp[30010] = { 0 };//当存体积为j时的,价值最大值for(int i=1;i<=m;i++)for (int j = n; j >= v[i]; j--)//当存到第i个时,花费为j时价值的最大值{dp[j] = max(dp[j], dp[j - v[i]] + p[i] * v[i]);//不选取i则继承存到第i-1个时的最大值,选取i则最大值更新为减去第i个花费时的最大值dp加上第i个的价值,即dp[j - v[i]] + p[i] * v[i]}cout << dp[n] << endl;
}
六、变2
代码:
#include<iostream>
#include<cstring>
using namespace std;
int main()
{int t;cin >> t;while (t--){int n, s;cin >> n >> s;long long f[500000], q[500000];//f记录j体积的最高战力,q记录j体积的精灵数量memset(f, 0, sizeof(f)), memset(q, 0, sizeof(q));for (int i = 1; i <= n; i++){int w, v;cin >> w >> v;for (int j = s; j >= w; j--){if (f[j] < f[j - w] + v)//装该精灵战力更高,则更新{f[j] = f[j - w] + v;q[j] = q[j-w]+1;}}}cout << f[s] << " "<<q[s]<<endl;}
}
七、变3
代码:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int a[105], f[25005];//f[i]表示价值i是否可以表示
int main()
{int t;cin>>t;while (t--){int n;cin >> n;int ans = n;for (int i = 1; i <= n; i++)cin >> a[i];sort(a + 1, a + n + 1);//从小到大排序memset(f, 0, sizeof(f));//清空为0f[0] = 1;for (int i = 1; i <= n; i++){if (f[a[i]] == 1)//a[i]该数值可以被之前表示,则ans--,这个票不需要用到{ans--;continue;}for (int k = a[i]; k <= a[n]; k++)//a[i]该数值不可以被表示,则从该数值到最大值,将加上a[i]后可以表示的数赋值为1{f[k] = f[k] || f[k - a[i]];}}cout << ans << endl;}
}