01背包问题——

版权声明:个人博客:www.jingyile.cn 萌新发博文积累经验,欢迎各位大佬指导!!! https://blog.csdn.net/JYL1159131237/article/details/78884312

01背包题目的雏形是:

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

从这个题目中可以看出,01背包的特点就是:每种物品仅有一件,可以选择放或不放。

其状态转移方程是:

f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}

对于这方方程其实并不难理解,方程之中,现在需要放置的是第i件物品,这件物品的体积是c[i],价值是w[i],因此f[i-1][v]代表的就是不将这件物品放入背包,而f[i-1][v-c[i]]+w[i]则是代表将第i件放入背包之后的总价值,比较两者的价值,得出最大的价值存入现在的背包之中。

 

题目描述:

假设山洞里共有a,b,c,d ,e这5件宝物(不是5种宝物),它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,现在给你个承重为10的背包, 怎么装背包,可以才能带走最多的财富。

有编号分别为a,b,c,d,e的五件物品,它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?

    此例题参考博客:动态规划之01背包问题(最易理解的讲解)

先对表进行大概的说明,前面三列是物品名字,重量和价值。后面1到10表示背包容量。

e3表示背包容量为3,当前物品为e。 装不下

d3表示背包容量为3,当前物品为e,d。装不下

c3表示背包容量为3,当前物品为e,d,c。 装不下

b3表示背包容量为3,当前物品为e,d,c,b 可以装b物品,所以值为b物品的价值3

a3表示背包容量为3,当前物品为e,d,c,b ,a 这时根据状态转移方程,比较b3和b1+a的价值的值。

后者更大,所以a3值为6.

当时看了上面博客的讲解后自己画出了上面这张表,可是比较好奇为什么要从最后一件物品开始往里面装,不能从第一件物品直接开始装嘛?

于是再次从第一件物品以同样的填法进行填表,发现其实结果是一样的,并没有影响。

这里对e8进行说明,d8为11,当前容量8减去e的重量4=4,所以寻找d4值 为9  9+6=15>11 所以e8的值更新为15

一道例题:有一个容量为m(1<=m<=4000000)的背包,有n(1<=n<=16)个物品,每个物品有体积v(1<=v<=2012)和价值w(0<=2012),现在要你选择一些物品,使得背包所装物品的总价值最大。

C++代码:

 

#include <iostream>
#include <memory.h>
using namespace std;
struct wupin
{
    int v;//体积
    int w;//价值
}a[10000];
int dp[10000][10000];
int main()
{
    int n,m;
    cin>>m>>n;
    memset(dp,0,sizeof(dp));
    memset(a,0,sizeof(a));
    for(int i=1;i<=n;i++)
        cin>>a[i].v>>a[i].w;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(j>=a[i].v)
                dp[i][j]=max(dp[i-1][j],dp[i-1][j-a[i].v]+a[i].w);
            else
                dp[i][j]=dp[i-1][j];
        }
//    for(int i=1;i<=n;i++)
//       {
// for(int j=1;j<=m;j++)
//            cout<<dp[i][j]<<' ';
//            cout<<endl;
//       }
    cout << dp[n][m] << endl;
    return 0;
}

一般写法:

大小为j的背包是否放第i个物品,取决于大小为(j-a[i].v)的背包的最优解+a[i].w 是否大于当前不放这个物品的最优解的价值

 

#include <iostream>
#include <memory.h>
using namespace std;
struct wupin
{
    int v;//体积
    int w;//价值
}a[10000];
int dp[100000];
int main()
{
    int n,m;
    cin>>m>>n;
    memset(dp,0,sizeof(dp));
    memset(a,0,sizeof(a));
    for(int i=0;i<n;i++)
        cin>>a[i].v>>a[i].w;
    for(int i=0;i<n;i++)
        for(int j=m;j>=a[i].v;j--)
            dp[j]=max(dp[j],dp[j-a[i].v]+a[i].w);
    cout << dp[m] << endl;
    return 0;
}

 

最简洁的写法:

 

 

#include <cstdio>
#include <algorithm>
using namespace std;
int f[1005];
int n,m;
int main()
{
    int w,v;
    scanf("%d%d",&m,&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&v,&w);
        for(int j=m;j>=v;j--)
            f[j]=max(f[j],f[j-v]+w);
    }
    printf("%d\n",f[m]);
    return 0;
}

补充:求背包当前容量为m时,共有多少种不同选择。

例题:

问题 L: 动态规划进阶题目之神奇的口袋

时间限制: 1 Sec  内存限制: 64 MB
提交: 77  解决: 47
[提交][状态][讨论版][命题人:lyh]

题目描述

有一个神奇的口袋,总的容积是40,用这个口袋可以变出一些物品,这些物品的总体积必须是40。John现在有n个想要得到的物品,每个物品的体积分别是a1,a2……an。John可以从这些物品中选择一些,如果选出的物体的总体积是40,那么利用这个神奇的口袋,John就可以得到这些物品。现在的问题是,John有多少种不同的选择物品的方式。

输入

输入的第一行是正整数n (1 <= n <= 20),表示不同的物品的数目。接下来的n行,每行有一个1到40之间的正整数,分别给出a1,a2……an的值。

输出

输出不同的选择物品的方式的数目。

样例输入

3
20
20
20

样例输出

3
#include<bits/stdc++.h>
using namespace std;
int a[50];
int b[50][50];//b[i][j]表示从i件物品中凑出j体积的方法数
int main() {
	int n;
	cin>>n;
	int cnt=0;
	for(int i=1; i<=n; i++) {
		cin>>a[i];
		b[i][0]=1;
	}
	b[0][0]=1;
	for(int j=1; j<=40; j++)//遍历背包容量 
		for(int i=1; i<=n; i++) {
			b[i][j]=b[i-1][j];
			if(j>=a[i]) {
				b[i][j]+=b[i-1][j-a[i]];
			}
		}
	cout<<b[n][40];
	return 0;
}

 

 

 

 

 

 

 

 

展开阅读全文

没有更多推荐了,返回首页