动态规划法(入门题)——01背包问题

01背包问题(0-1 Knapsack Problem)


题意:先有价值为v_{i}、重量为w_{i}的N个物品以及容量为W的背包。选择装入包中的需满足:

  • 背包总价值尽可能得高
  • 背包总重量不超过W

输入 第1行输入2个整数N,W,空格隔开。接下来N行输入第i个物品的价值v_{i}与重量w_{i},每个物品占一行,相邻数值之间空格隔开。

输出 输出总价值的最大值,占1行

限制 1\leq N\leq 1001\leq v_{i}\leq 10001\leq w_{i}\leq 10001\leq W \leq 10000

输入示例

4 5

4 2

5 2

2 1

8 3

输出

12


题解分析

“选”与“不选”对每次的值进行更新。首先、我们要准备一些变量

struct Item{
	int v;
	int w;
}A[MAX+1];//用来存放物品信息
int dp[MAX+1][10001];//dp[i][j]代表前i个物品在容量为j时的最大价值  
//dp数组的初始化 
for(int i=0;i<=n;i++){
	for(int j=0;j<=W;j++)
		dp[i][j]=0;
}

设第i的物品进入了是否放入容量为j背包的考虑范围:

"不选":dp[i][j]=dp[i-1][j],“选”:dp[i][j]=dp[i-1][j-A[i].w]+A[i].v,选的时候需要为第i个物品提供空间。

取最大值:dp[i][j]=max(dp[i-1][j],dp[i-1][j-A[i].w]+A[i].v)

for(int i=1;i<=n;i++){
	for(int j=A[i].w;j<=W;j++)
		dp[i][j]=max(dp[i-1][j],dp[i-1][j-A[i].w]+A[i].v);
}

初始化的dp数组里的值:

vw012345
42000000
52000000
12000000
83000000

将A[1]放入容量由0到5的背包里:

vw012345
42004444
520     
120     
830     

 

将A[2]放入容器由0-5的背包里:

vw012345
42004444
52005599
120     
830     

最后形成:

vw012345
42004444
52005599
120257911
8302581013

代码部分为:

#include<iostream>
#include<algorithm>
using namespace std;
#define MAX 100
#define WMAX 10001
struct Item{
	int v;
	int w;
}A[MAX+1];
int n,dp[MAX+1][10001]; 
int main(){
	int n,W;//种数、总重
	cin>>n>>W;
	for(int i=1;i<=n;i++){
		cin>>A[i].v>>A[i].w;
	} 
	//dp数组的初始化 
	for(int i=0;i<=n;i++){
		for(int j=0;j<=W;j++)
			dp[i][j]=0;
	}
	for(int i=1;i<=n;i++){
		for(int j=A[i].w;j<=W;j++)
			dp[i][j]=max(dp[i-1][j],dp[i-1][j-A[i].w]+A[i].v);
	}
	cout<<dp[n][W]<<endl;
	return 0;
} 

敲了这么多天的代码,代码质量水准还是一成不变(为了解题而解题)。我们可以记录下是哪些物品被挑选。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
#define NMAX 105
#define WMAX 10005
#define DIAGONAL 1
#define TOP 0
struct Item{
	int value;
	int weight;
};
int N,W;
Item items[NMAX+1];
int C[NMAX+1][WMAX+1],G[NMAX+1][WMAX+1];
void compute(int &maxValue,vector<int>&selection){
	for(int w=0;w<=W;w++){
		C[0][w]=0;
		G[0][W]=DIAGONAL;
	}
	for(int i=1;i<=N;i++)
		C[i][0]=0;
	for(int i=1;i<=N;i++){
    	   for(int w=1;w<=W;w++){
           //默认没选上
	    	C[i][w]=C[i-1][w];
		    G[i][w]=TOP;
		    if(items[i].weight>w)
		    	continue;
		    if(items[i].value+C[i-1][w-items[i].weight]>C[i-1][w]){
			    C[i][w]=C[i-1][w-items[i].weight]+items[i].value;
			    G[i][w]=DIAGONAL;
		    }
		}
	}
	maxValue=C[N][W];
    //完成统计操作
	selection.clear();
	for(int i=N,w=W;i>=1;i--){
		if(G[i][w]==DIAGONAL){
			selection.push_back(i);
			w-=items[i].weight;
		}	
	}
    //追本溯源
	reverse(selection.begin(),selection.end());
}
void input(){
	cin>>N>>W; 
	for(int i=1;i<=N;i++){
		cin>>items[i].value>>items[i].weight;
	}
}
int main(){
	int maxValue;
	vector<int>selection;
	input();
	compute(maxValue,selection);
	cout<<maxValue<<endl;
	vector<int>::iterator it;
	for(it=selection.begin();it!=selection.end();it++){
		cout<<*(it)<<" ";	
	}
	cout<<endl;
	return 0;
} 

加油!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值