1.背包问题
有 NN 件物品和一个容量是 VV 的背包。每件物品只能使用一次。
第 ii 件物品的体积是 vivi,价值是 wiwi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。输入格式:
第一行两个整数,N,VN,V,用空格隔开,分别表示物品数量和背包容积。
接下来有 NN 行,每行两个整数 vi,wivi,wi,用空格隔开,分别表示第 ii 件物品的体积和价值。
输出格式:
输出一个整数,表示最大价值。
数据范围:
0<N,V<=1000
0<vi,wi<=1000
ac代码:
#include<stdio.h>
#include<stdlib.h>
int n,v;
int vi[1010],wi[1010];
int dp[1010];
int main(){
int i=1,j;
scanf("%d%d",&n,&v);
while(i<=n){
scanf("%d %d",&vi[i],&wi[i]);//vi表示重量,wi表示价值
i++;
}
for(i=1;i<=n;i++){
for(j=v;j>0;j--){//表示现在还可以放入的重量
if(j>=vi[i])
//如果还可以放入的重量大于等于第i个物品的重量
//则可以考虑把物品i放入
if(dp[j]<dp[j-vi[i]]+wi[i])//如果当前可放入j重量条件下,
//背包的价值小于当前背包重量减掉物品i重量后的价值加上物品i的质量
//则修改背包的j的价值
dp[j]=dp[j-vi[i]]+wi[i];
}
}
//输出当背包可容纳重量为v的时候的最大价值
printf("%d\n",dp[v]);
return 0;
}
2.完全背包问题
有 NN 种物品和一个容量是 VV 的背包,每种物品都有无限件可用。
第 ii 种物品的体积是 vivi,价值是 wiwi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。输入格式:
第一行两个整数,N,VN,V,用空格隔开,分别表示物品数量和背包容积。
接下来有 NN 行,每行两个整数 vi,wivi,wi,用空格隔开,分别表示第 ii 件物品的体积和价值。
输出格式:
输出一个整数,表示最大价值。
数据范围:
0<N,V<=1000
0<vi,wi<=1000
思路整理:
ac代码:
#include<stdio.h>
#include<stdlib.h>
int n,v;
int vi[1010],wi[1010];
int dp[1010];
int max(int a,int b){
return a>b?a:b;
}
int main(){
int i=1,j;
scanf("%d%d",&n,&v);
while(i<=n){
scanf("%d %d",&vi[i],&wi[i]);//vi表示重量,wi表示价值
i++;
}
for(i=1;i<=n;i++){
for(j=1;j<=v;j++){
dp[j]=dp[j];
if(j>=vi[i]){
dp[j]= max(dp[j],dp[j-vi[i]]+wi[i]);
}
}
}
printf("%d\n",dp[v]);
return 0;
}
3.多重背包问题
有 NN 种物品和一个容量是 VV 的背包。
第 ii 种物品最多有 sisi 件,每件体积是 vivi,价值是 wiwi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。输入格式:
第一行两个整数,N,VN,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 NN 行,每行三个整数 vi,wi,sivi,wi,si,用空格隔开,分别表示第 ii 种物品的体积、价值和数量。
输出格式:
输出一个整数,表示最大价值。
数据范围:
0<N,V<=1000
0<vi,wi,si<=1000
思路:
强拆,在数据较小情况下,直接把数量转化为单个有体积价值的物品
ac代码:
#include<stdio.h>
#include<stdlib.h>
#define N 10010
int n,v,w,k,s;
int vi[N],wi[N];
int dp[N];
int t;
int max(int a,int b){
return a>b?a:b;
}
int main(){
int i=1,j;
scanf("%d%d",&n,&v);
while(i<=n){
scanf("%d%d%d",&k,&w,&s);
while(s--){
vi[++t]=k;
wi[t]=w;
}
i++;
}
for(i=1;i<=t;i++){
for(j=v;j>=vi[i];j--){
dp[j]= max(dp[j],dp[j-vi[i]]+wi[i]);
}
}
printf("%d\n",dp[v]);
return 0;
}
#include <iostream>
using namespace std;
const int N = 110; // 数组的大小,取值稍大于数据范围即可
int n, m; // 变量 n,m 来获取物品的数量以及背包的容量
int f[N]; // 一维数组 dp[j] 表示背包的容量为 j 时所能获取的最大价值
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++) // i 循环让考虑物品的数量不断增加
{
int v, w, s; // 三个变量 v,w,s 分别获取每个物品的体积、价值与数量,在循环内部边更新边处理
cin >> v >> w >> s;
for (int j = m; j >= v; j--) // j 循环让背包的最大容量不断增加
{
for (int k = 1; k <= s && k * v <= j; k++)
// k 循环让选用当前物品的数量不断增加,k不能大于物品最大数量s,k * v不能大于当前循环的背包容量 j
{
f[j] = max(f[j], f[j - v * k] + w * k);
}
}
}
cout << f[m] << endl;
return 0;
}
4.多重背包问题2
有 NN 种物品和一个容量是 VV 的背包。
第 ii 种物品最多有 sisi 件,每件体积是 vivi,价值是 wiwi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。输入格式:
第一行两个整数,N,VN,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 NN 行,每行三个整数 vi,wi,sivi,wi,si,用空格隔开,分别表示第 ii 种物品的体积、价值和数量。
输出格式:
输出一个整数,表示最大价值。
数据范围:
0<N≤10000<N≤1000
0<V≤20000<V≤2000
0<vi,wi,si≤2000
#include <stdio.h>
#include <stdlib.h>
#define N 12000
#define M 2010
int n,m;
int vi[N],wi[N];
int dp[N];
int max(int a,int b){
return a>b?a:b;
}
int main(){
int a,b,s,i,j,k;
scanf("%d %d",&n,&m);
int cnt =0;
for(i=1;i<=n;i++){
scanf("%d %d %d",&a,&b,&s);
k=1;
while(k<=s){
vi[++cnt] = a*k;
wi[cnt] = b*k;
s-=k;
k*=2;
}
if(s>0){
vi[++cnt] = a*s;
wi[cnt] = b*s;
}
}
n=cnt;//更新n
for(i=1;i<=n;i++){
for(j=m;j>=vi[i];j--){
dp[j] = max(dp[j],dp[j-vi[i]]+wi[i]);
}
}
printf("%d",dp[m]);
return 0;
}
5.分组背包问题
有 NN 组物品和一个容量是 VV 的背包。
每组物品有若干个,同一组内的物品最多只能选一个。
每件物品的体积是 vijvij,价值是 wijwij,其中 ii 是组号,jj 是组内编号。求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式:
第一行有两个整数 N,VN,V,用空格隔开,分别表示物品组数和背包容量。
接下来有 NN 组数据:
- 每组数据第一行有一个整数 SiSi,表示第 ii 个物品组的物品数量;
- 每组数据接下来有 SiSi 行,每行有两个整数 vij,wijvij,wij,用空格隔开,分别表示第 ii 个物品组的第 jj 个物品的体积和价值;
输出格式:
输出一个整数,表示最大价值。
数据范围:
0<N,V≤1000<N,V≤100
0<Si≤1000<Si≤100
0<vij,wij≤100
ac代码:
#include <stdio.h>
#define N 110
int n,m;
int i,j,k;
int dp[N],vi[N],wi[N];
int max(int a,int b){
return a>b?a:b;
}
int main(){
scanf("%d %d",&n,&m);
while(n--){//分组
scanf("%d",&k);
//输入组内的每一个物品的价值和体积
for(i=0;i<k;i++)
scanf("%d %d",&vi[i],&wi[i]);
for(j=m;j>=0;j--){//把关于体积变化循环放在外面便于输出每次分组的最大值
//同时,不能只一个循环 查找dp【m】是因为多重分组,因此第一组的最优解和第二组的搭配在一起可能不如
//其他的解搭配,所以需要遍历初始化,dp【j】
for(i=0;i<k;i++){
if(j>=vi[i])
dp[j] = max(dp[j],dp[j-vi[i]]+wi[i]);
printf("dp[%d] = %d",j,dp[j]);
}
printf("\n");
}
}
printf("%d\n",dp[m]);
return 0;
}