C++详解背包问题,动态规划的一种典型形式

标准背包
说明
有一个背包能装的重量maxw(正整数,0≤maxw≤20000),同时有n件物品(0≤n≤100),每件物品有一个重量wi(正整数)和一个价值pi(正整数)。要求从这n件物品中任取若干件装入背包内,使背包的物品价值最大。

输入格式
第1行:背包最大载重maxw,物品总数n
第2行到第n+1行:每个物品的重量和价值。

输出格式
一个数字即背包内物品最大价值。

样例
输入数据 1
10 3
4 5
3 4
6 9
输出数据 1
14

#include <bits/stdc++.h>
using namespace std;
const int mm=20100;
const int mn=110;
int w[mn],p[mn];
int f[mm];
int n,m,i,j;
int main()
{
    
    
	cin>>m>>n;
	for(i=1;i<=n;i++) cin>>w[i]>>p[i]; 
	for (i=0; i<=m; i++) f[i]=0;// 初值
	for (i=1; i<=n; i++)
		for (j=m; j>=w[i]; j--)
			f[j]=max(f[j],f[j-w[i]]+p[i]);
	cout<<f[m];
	return 0;
}

极简背包问题
说明
极简单的背包问题。
设有一个背包,可以放入的重量为s。现有n件物品,重量分别为w_1,w_2…,w_n,(1≤i≤n)w
1

,w
2

…,w
n

,(1≤i≤n) 均为正整数,从n件物品中挑选若干件,使得放入背包的重量之和正好为s。

输入格式
第一行两个整数包括放入的物品重量为s(s<=32767)和物品的件数n(n<=50);
第二行n个整数,表示每件物品的重量(输入数据均为正整数)

输出格式
若满足条件则输出"YES",若不满足则输出"NO"。

样例
输入数据 1
20 5
1 3 5 7 9
输出数据 1
YES

#include<bits/stdc++.h>
using namespace std;
int s,n,w[51],f[51];
bool flag;
void dfs(int i,int step){
    
    
	f[step] = w[i];
	int sum = 0;
	for(int k=1;k<=step;k++){
    
    
		sum = sum + f[k];
	}
	if(sum==s){
    
    
		flag = 1;
		return;
	}
	for(int k=i+1;k<=n;k++){
    
    
		if(flag==0 && sum<s) dfs(k,step+1);
 	}
}
int main(){
    
    
	cin>>s>>n;
	for(int i=1;i<=n;i++){
    
    
		cin>>w[i];
	}
	for(int i=1;i<=n;i++){
    
    
		memset(f,0,sizeof(f));
		dfs(i,1); 
		if(flag==1) break;
	}
	if(flag==1) cout<<"YES";
	else cout<<"NO";
	return 0;
}


多重背包(1)
说明
有N种物品和一个容量是V的背包。
第i种物品最多有si件,每件体积是vi,价值是wi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。

输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。0 \lt N,V \le 100 ,0 \lt vi,wi,si \le 1000<N,V≤100,0<vi,wi,si≤100

输出格式
输出一个整数,代表最大价值。

样例
输入数据 1
4 10
3 2 2
4 3 2
2 2 1
5 3 4
输出数据 1
8

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

int v[110],w[110],f[110],s[110];

int main() {
    
    
	int n,m;
	cin>>n>>m;
	for(int i = 1;i <= n;i++){
    
    
		cin>>v[i]>>w[i]>>s[i];
	} 
	
	//循环i件物品
	for(int i = 1; i <= n; i++) {
    
    
		//每种物品有si件,可以认为有s[i]个物品
		for(int k = 1;k <= s[i];k++){
    
    
			//逆序循环背包容量,转换为01背包
			for(int j = m;j >= v[i];j--){
    
    
				f[j] = max(f[j],f[j-v[i]]+w[i]);
			} 
		} 
	}
	
	cout<<f[m];
}

多重背包(2)
说明
有N种物品和一个容量是V的背包。
第i种物品最多有si件,每件体积是vi,价值是wi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。

输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。

接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。

输出格式
输出一个整数,表示最大价值。

0<N≤1000
0<V≤2000
0<vi,wi,si≤2000

样例
输入数据 1
4 5
1 2 3
2 4 1
3 4 3
4 5 2
输出数据 1
10

#include <bits/stdc++.h>
using namespace std;
//由于要将物品拆分 
int f[2020],v[15050],w[15050];
int op = 0;
int main() {
    
    
	//二进制优化 
	//7:表示为0~7的和
	//7分为:1 1 1 1 1 1 1,将7件物品分为7种物品 
	//二进制分法:2^2+2^1+2^0
	//凑出一个整数Si的时间复杂度:log2(Si)
	
	/*
	  如果要凑一个整数10
	  理论上需要log2(10)=4个数
	  但4个数1 2 4 8,不过会多凑一些数出来
	  但其实需要的数是: 1 2 4 3就能凑出0~10
	  也就是说:2^p是<=Si 2^p+1 > Si,求出一个p
	    这个p就是需要的数的数量
		需要的最后一个数 = Si - (2^0+2^1+...+2^p) 
	*/ 
	int n,m;
	cin>>n>>m;
	//拆分物品 
	for(int i = 1;i <= n;i++){
    
    
		int v1,w1,s;
		cin>>v1>>w1>>s;
		int k = 1;//k代表2的幂 
		while(k <= s){
    
    
			v[++op] = v1 * k;
			w[op] = w1 * k; 
			s -= k;
			k *= 2;
		} 
		//如果s还有值,说明s不是正好是2的整数次方 
		if(s){
    
    
			v[++op] = v1 * s;
			w[op] = w1 * s;
		}
	}
	
	//转换为01背包
	for(int i = 1;i <= op;i++){
    
    
		for(int j = m;j >= v[i];j--){
    
    
			f[j] = max(f[j],f[j-v[i]]+w[i]); 
		}
	} 
	
	cout<<f[m];
	 
	return 0;
}


混合背包
说明
有 N 种物品和一个容量是 V 的背包。

物品一共有三类:
第一类物品只能用1次(01背包);
第二类物品可以用无限次(完全背包);
第三类物品最多只能用 si 次(多重背包);
每种体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。

输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。
si=−1 表示第 i 种物品只能用1次;
si=0 表示第 i 种物品可以用无限次;
si>0 表示第 i 种物品可以使用 si 次;

输出格式
一个整数,表示最大价值。

样例
输入数据 1
4 5
1 2 -1
2 4 1
3 4 0
4 5 2
输出数据 1
8
数据范围
0<N,V≤1000
0<vi,wi≤1000
−1≤si≤1000

#include <bits/stdc++.h>
using namespace std;
int n,V;
struct kk {
    
    
	int w,v,m;
};
kk a[1001];
int f[20001];
void completebag(int v,int w) {
    
    
	for(register int i=v; i<=V; ++i)
		f[i]=max(f[i],f[i-v]+w);
	return;
}
void zeronebag(int v,int w) {
    
    
	for(register int i=V; i>=v; --i)
		f[i]=max(f[i],f[i-v]+w);
	return;
}
void multiplebag(int v,int w,int m) {
    
    
	if(m*v>V) {
    
    
		completebag(v,w);
		return;
	}
	int k=1;
	while(k<=m) {
    
    
		zeronebag(v*k,w*k);
		m-=k;
		k*=2;
	}
	zeronebag(v*m,w*m);
	return;
}
int main() {
    
    
	scanf("%d%d",&n,&V);
	for(register int i=1; i<=n; ++i)
		scanf("%d%d%d",&a[i].v,&a[i].w,&a[i].m);
	memset(f,0x0,sizeof(f));
	for(register int i=1; i<=n; ++i) {
    
    
		if(a[i].m==-1) zeronebag(a[i].v,a[i].w);
		if(a[i].m==0) completebag(a[i].v,a[i].w);
		if(a[i].m>0) multiplebag(a[i].v,a[i].w,a[i].m);
	}
	printf("%d\n",f[V]);

	return 0;
}


猜你喜欢

转载自blog.csdn.net/yaosichengalpha/article/details/131573659