动态规划之'01背包'

致敬前辈!参考网址:
https://blog.csdn.net/qq_38410730/article/details/81667885

状态转移方程:

if (背包体积j小于物品i的体积)
    f[i][j] = f[i-1][j] //背包装不下第i个物体,目前只能靠前i-1个物体装包
else
    f[i][j] = max(f[i-1][j], f[i-1][j-Vi] + Wi)

问题描述:

有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。

基本思路 :
这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。 用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:tab[i][j] = max(tab[i-1][j-weight[i]]+value[i],tab[i-1][j]) ({i,j|0<i<=n,0<=j<=total})

其中i表示放第i个物品,j表示背包所容纳的重量,那么tab[i-1][j-weight[i]]+value[i]表示放入第i物品,刚开始接触会有疑问,tab[i-1][j-weight[i]]这个值,可以这样理解:tab[i-1][j]为装到上一个物品在背包j容量时的最佳值,那么如果我要求在j容量的时候放入现在的i物品的价值,那么是不是要先得到容量为(j-weight[i])时候的价值,即先得到 tab[i-1][j-weight[i]] ,所以 tab[i-1][j-weight[i]]+value[i] 为放入第i物品的价值; tab[i-1][j] 就是不放入第i个物品。

#include<iostream>
using namespace std;
#include <algorithm>
 
int main()
{
	int w[5] = { 0 , 2 , 3 , 4 , 5 };			//商品的体积2、3、4、5
	int v[5] = { 0 , 3 , 4 , 5 , 6 };			//商品的价值3、4、5、6
	int bagV = 8;					        //背包大小
	int dp[5][9] = { { 0 } };			        //动态规划表
 
	for (int i = 1; i <= 4; i++) {
		for (int j = 1; j <= bagV; j++) {
			if (j < w[i])
				dp[i][j] = dp[i - 1][j];
			else
				dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]);
		}
	}
 
	//动态规划表的输出
	for (int i = 0; i < 5; i++) {
		for (int j = 0; j < 9; j++) {
			cout << dp[i][j] << ' ';
		}
		cout << endl;
	}
 
	return 0;
}

最终综合版,既能打表也能查找组成元素:

#include<iostream>
using namespace std;
#include <algorithm>
 
int w[5] = { 0 , 2 , 3 , 4 , 5 };			//商品的体积2、3、4、5
int v[5] = { 0 , 3 , 4 , 5 , 6 };			//商品的价值3、4、5、6
int bagV = 8;					        //背包大小
int dp[5][9] = { { 0 } };			        //动态规划表
int item[5];					        //最优解情况
 
void findMax() {					//动态规划
	for (int i = 1; i <= 4; i++) {
		for (int j = 1; j <= bagV; j++) {
			if (j < w[i])
				dp[i][j] = dp[i - 1][j];
			else
				dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]);
		}
	}
}
 
void findWhat(int i, int j) {				//最优解情况
	if (i >= 0) {
		if (dp[i][j] == dp[i - 1][j]) {
			item[i] = 0;
			findWhat(i - 1, j);
		}
		else if (j - w[i] >= 0 && dp[i][j] == dp[i - 1][j - w[i]] + v[i]) {
			item[i] = 1;
			findWhat(i - 1, j - w[i]);
		}
	}
}
 
void print() {
	for (int i = 0; i < 5; i++) {			//动态规划表输出
		for (int j = 0; j < 9; j++) {
			cout << dp[i][j] << ' ';
		}
		cout << endl;
	}
	cout << endl;
 
	for (int i = 0; i < 5; i++)			//最优解输出
		cout << item[i] << ' ';
	cout << endl;
}
 
int main()
{
	findMax();
	findWhat(4, 8);
	print();
 
	return 0;
}

样题:HDU2602 Bone Collector(我用一维数组来写)

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define mem(a) memset(a,0,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
		ll w[1005];
		ll v[1005];
		ll dp[1005];
int main() 
{
#ifdef Local
	freopen("../input.in", "r", stdin);
    freopen("../output.out", "w", stdout);
#endif
	int N;
	cin>>N;
	while(N--){
		ll n,bagv;
		cin>>n>>bagv;

		mem(dp);mem(w);mem(v);
		w[0]=0;v[0]=0;
		for(ll i=1;i<=n;i++){
			cin>>v[i];
		}
		for(ll i=1;i<=n;i++){
			cin>>w[i];
		}
		for(ll i=1;i<=n;i++){
			for(ll j=bagv;j>=0;j--){
				if(j>=w[i]){
					dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
				}
			}
		}
		cout<<dp[bagv]<<endl;
	}
}

二维数组的写法(ps:记得有些物品重量为0但依然有可能有价值!!)

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define mem(a) memset(a,0,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
		ll w[1005];
		ll v[1005];
		ll dp[1005][1005];
int main() 
{
#ifdef Local
	freopen("../input.in", "r", stdin);
    freopen("../output.out", "w", stdout);
#endif
	int N;
	cin>>N;
	while(N--){
		ll n,bagv;
		cin>>n>>bagv;

		mem(dp);mem(w);mem(v);
		w[0]=0;v[0]=0;
		for(ll i=1;i<=n;i++){
			cin>>v[i];
		}
		for(ll i=1;i<=n;i++){
			cin>>w[i];
		}
		for(ll i=1;i<=n;i++){
			for(ll j=0;j<=bagv;j++){
				if(j<w[i]){
					dp[i][j]=dp[i-1][j];
				}
				else{
					dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);	
				}
			}
		}
		cout<<dp[n][bagv]<<endl;
	}
}
发布了71 篇原创文章 · 获赞 5 · 访问量 3416

猜你喜欢

转载自blog.csdn.net/Rainfoo/article/details/102638384