Kingsman C++背包问题系统解析

背包问题系统题解

  • 一、01背包问题(背包问题根源)
    • 二、完全背包问题
      • 三、多重背包问题
        • 四、多重背包问题的优化

一、01背包问题(背包问题根源)

描述
一个小偷进入超市,带一个最多能装 M 公斤的背包,现在有 n 件物品,它们的重量分别是blablaba,求背包最大价值
在这里插入图片描述

输入
第一行:两个整数,M(背包容量, M ≤ 200 M≤200 M200)和N(物品数量,N≤30);
第2到N+1行:每行二个整数,表示每个物品的重量和价值。

输出
仅一行,一个数,表示最大总价值。
代码如下所示,可参考注释加以理解

#include<iostream>
using namespace std;
int w[100000];
//输入用的两个数组 
int v[100000];
//w数组用作记录重量,v记录价值 
int f[1000][1000];
//二维数组f含义是放X个物品,重X,内部保存总价值 
int main()
{
	int m,n;
	//定义物品数量n,包最大容量m 
	cin>>m>>n;
	// 给这两个变量赋值(输入) 
	for(int i=1;i<=n;i++)
	//用数组下标习惯上从一开始 
	{	// 因为用0很容易越界,出现问题 
		cin>>w[i]>>v[i];
		//for循环输入每样物品的重量和价值
		
	}
	for(int i=1;i<=n;i++) 
	{//次数==物品数,对每个物品处理
		for(int j=0;j<=m;j++) 
		{//从零开始遍历背包物品的总重量(m) 
			f[i][j]=f[i-1][j];
	//f[i][j]初始值设置为放新东西之前的价值 (准备背包) 
			if(j>=w[i])
			//判断包里剩余的空间够不够 
			{
				//执行到括号内表示空间足够 
			        if(f[i][j]<f[i-1][j-w[i]]+v[i])
					//判断放入第i物品后价值是否比原来大
					//不等式前一截表示放入i物品前的总价值
					//后一截表示放入后的价值 
                    f[i][j]=f[i-1][j-w[i]]+v[i];
                     // 如果价值更大,就要放进来 
			}
		}
	}
	cout<<f[n][m];//输出最大价值 
}

二、完全背包问题

一个小偷有一个最多能装 M 公斤的背包,现在有 n 种物品,它们的重量分别是blablabla,价值分别是blablabla,如果每种物品都可以取任意件,求小偷能获得最大总价值。

分析来看,这题与01背包不同,01背包模型为要么有要么无,但这个多了对数量的分析。但是和01背包的差别不大,再加一个用来判断数量的for循环就可以了。
代码如下:(’ ~ ')↓↓↓↓

#include <bits/stdc++.h>
using namespace std;
int m,n;
int dp[1010][1010];
int w[1000000];//weight
int v[1000000];//value
int main()
{
	cin>>m>>n;
	for(int i=1;i<=n;i++)
	{
		 cin>>w[i]>>v[i];
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<=m;j++)
		{
			for(int k=0;k*w[i]<=j;k++)
			{
				dp[i][j]=max(dp[i][j],dp[i-1][j-k*w[i]]+k*v[i]);
			}
		}
	}
	cout<<dp[n][m];
}

三、多重背包问题

有N种物品和一个容量是V的背包。
第 i种物品最多有 Si件,每件体积是vi,价值是wi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。
输入格式
第一行两个整数,N,V用空格隔开,分别表示物品种数和背包容积。
接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i种物品的体积、价值和数量。
输出格式
输出一个整数,表示最大价值.
分析来看,三种背包问题基本架构相似,多重背包是完全背包的更进一步外延,并且看上去差别不大。学习动态规划没有可背的代码,需要我们多敲代码,做到能理解每一句,背写,并且成功运行,在一次次练习中渐渐才有创新的能力。
代码如下:

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2000;
int w[MAXN], v[MAXN],s[MAXN], f[MAXN];   
int main() 
{
    int n,m;
    cin >> n >> m;
    for(int i = 1; i <= n; ++i) 
        cin >> w[i] >> v[i] >> s[i];
    for(int i = 1; i <= n; ++i)
        for(int j = m; j>=0; --j)   
	 for(int k = 1; k <= s[i]; ++k) 
	 if(j>=k*w[i])
    f[j] = max(f[j], f[j-k*w[i]]+k*v[i]);
    cout << f[m] << endl;
    return 0;
}

四、多重背包问题的优化

DP算法虽然有些许难懂复杂,高大上的感觉,但是它最大的问题是他的时间复杂度过高,因此无论是在奥赛中还是工程中都对数据规模有限制,但是DP可以被优化,减小他的时间复杂度和空间复杂度,就是让它不费多余的数组,不费更多的时间。
对多重背包问题的二进制优化代码如下:

#include <iostream>
using namespace std;
const int N=10010, V=2010;
int dp[V], v[N], w[N];
int main(){
    int n, m, k=0;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        int vx,wx,s;   
        cin>>vx>>wx>>s;
        for(int j=1;j<=s;j=j*2){
            v[++k]=j*vx;
            w[k]=j*wx;
            s-=j;
        }
        if(s>0){
            v[++k]=s*vx;
            w[k]=s*wx;
        }
    }
    n=k;
    for(int i=1;i<=n;i++){
        for(int j=m;j>=v[i];j--){
            dp[j]=max(dp[j], dp[j-v[i]]+w[i]);
        }
    }
    cout<<dp[m];
}

在这里插入图片描述

文章结束,这里提供一些资源:
1.网址好记的在线编辑各种语言的网站:
dooccn.com
让您随时随地,在同学面前想装X就装!
2.由NOIP金牌得主开发的代码网站(强烈推荐!!!!):
acwing.com
支持限时编程挑战,天梯匹配在线代码对战,以及奥赛刷题,并且有无数题解+视频+课程
3.

你可能感兴趣的:(题解,程序设计,c++,算法,动态规划,动态规划求解)