背包问题(01背包,01背包优化,完全背包,分组背包)

01背包问题

一个物品要么放入背包,要么就不放入背包,在背包容量有限的情况下得到最大的价值(权重)

状态转移方程:dp[i][j]=max(dp[i-1][j],dp[i-1][j-ci]+wi)
dp[i][j]表示加入第i个物品后容量为j的最大价值,=max(不加入第i个物品的价值,加入第i个物品的价值)

#include<iostream>
#include<cstring>
#include<stdio.h>
#include<vector>
#include<algorithm>
#include<math.h>
#include<iomanip>
#include<map>
#define MAX(a,b) ((a)>(b)?(a):(b))
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define ll long long int
using namespace std;
const int N = 25;
int dp[N][N];
int c[N];
int w[N];
int main()
{
 	//ios::sync_with_stdio(false);
	//cin.tie(0); cout.tie(0);
	int i,j;
	int v,n;
	cin>>v>>n;
	for(i=1;i<=n;i++){
		cin>>c[i]>>w[i];
	}
	//初始状态
	//当背包容量为0时,价值为0、当背包里面没有物品时,价值同样为0;
	for(i=0;i<=N;i++){
		dp[i][0]=0;
		dp[0][i]=0;
	}
	int maxx=0;
	for(i=1;i<=n;i++){//放入第i个物品后 最大容量的最优解 
		for(j=1;j<=v;j++){
			if(j<c[i])
				dp[i][j]=dp[i-1][j];
			dp[i][j]=max(dp[i-1][j],dp[i-1][j-c[i]]+w[i]);
		}
	}
	cout<<dp[n][v]<<endl;
	//get_loaction 
	/*
	j=v;
	for(i=n;i>0;i--){
		if(dp[i][j]>dp[i-1][j]){
			cout<<i<<' ';
			j-=c[i];
		}	
	}
	cout<<"\n";
	*/
	return 0;
 }

01背包问题的优化

在01背包问题的基础上进行优化,因为每加入一个物品,dp[][]都是从左往右,从上到下进行计算的,即当计算第i个物品时,它只与第i-1个物品相关,可以用一维的dp[]从右往左计算,简单的设想一下放入0个物品时,dp[]={0,0,0,0,0,0};当放入1个物品(weight=2,value=2)后dp[]={0,0,2,2,2,2},放入第2个物品(weight=3,4) dp[]={0,0,2,3,3,6},依次类推,右边的值只和左边的值有关,而左边的值是上一次更新过的。

#include<iostream>
#include<cstring>
#include<stdio.h>
#include<vector>
#include<algorithm>
#include<math.h>
#include<iomanip>
#include<map>
#define MAX(a,b) ((a)>(b)?(a):(b))
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define ll long long int
using namespace std;
const int N = 25;
int dp[N]={0}; 
int c[N];
int w[N];
int main()
{
 	//ios::sync_with_stdio(false);
	//cin.tie(0); cout.tie(0);
	int i,j;
	int v,n;
	cin>>v>>n;
	for(i=1;i<=n;i++){
		cin>>c[i]>>w[i];
	}
	for(i=1;i<=n;i++){
		for(j=v;j>=c[i];j--){
			dp[j]=max(dp[j],dp[j-c[i]]+w[i]);
		}
	}
	cout<<dp[v]<<endl;
	return 0;
 }

完全背包

与01背包类似,但是每个物品时无限的
核心代码

	for(i=1;i<=n;i++){
		for(j=c[i];j<=v;j++){
			dp[i][j]=dp[i-1][j];
			for(int k=1;k*c[i]<=j;k++){
			dp[i][j]=max(dp[i][j],dp[i-1][j-k*c[i]]+w[i]);
			}
			} 
		}
	}

分组背包

与01背包问题类似,但是每个物品都有固定的分组,每组内的物品互斥,即每组最多只能取一个物品。

#include<iostream>
#include<cstring>
#include<stdio.h>
#include<vector>
#include<algorithm>
#include<math.h>
#include<iomanip>
#include<map>
#include<stack>
#include<queue>
#include<set>
#define MAX(a,b) ((a)>(b)?(a):(b))
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define mkp make_pair
#define ll long long int
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
using namespace std;
const int N = 1e3+10;
int a[N]={0},b[N]={0},c[N]={0},p[N][N]={0};
int dp[N]={0};
int main()
{
 	//freopen("aa.in","r",stdin);
	//freopen("aa.out","w",stdout);
 	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	int i,j,m,n,t=0;
	cin>>m>>n;
	for(i=1;i<=n;i++){
		cin>>a[i]>>b[i]>>c[i];//体积,价值,分组
		t=max(t,c[i]);//记录最大的分组 
		p[c[i]][0]++;//记录每组物品的数量 
		p[c[i]][ p[c[i]][0]]=i;
	} 
	for(i=1;i<=t;i++){
		for(int v=m;v>=0;v--){
			for(j=1;j<=p[i][0];j++){
				int k=p[i][j];
				if(a[k]<=v)
					dp[v]=max(dp[v],dp[v-a[k]]+b[k]);
			}
		}
	}
	cout<<dp[m]<<endl;
	return 0;
 }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值