您的位置:首页 > 其它

动态规划之背包问题

2017-01-21 14:55 176 查看
一、01背包

1.雏形:有N件物品和一个容量为v的背包,第i件物品体积为c[i],价值为w[i]。求怎样能使背包的物品价值最大?

2.特点:每件物品只有一件,可以选择放(1)或不放(0)

3.状态转移方程:

二维:F[i][v]=max{F[i-1][v],F[i-1][v-c[i]]+w[i]}

F[i][v]表示前i件物品恰放入一个容量为v的背包可获得的最大价值,

前者是不放第i件(前i-1件)放入容量为v的背包中的总价值,

后者是前i-1件的总价值+第i件的价值。

一维(空间优化):F[v]=max{F[v],F[v-c[i]]+w[i]}

4.例题

采药

input

输入的第一行有两个整数T(1 <= T <= 1000)和M(1 <= M <= 100),

用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。

接下来的M行每行包括两个在1到100之间(包括1和100)的整数,

分别表示采摘某株草药的时间(1 <= t <= T)和这株草药的价值(1 <= v <= 100000)。

output

输出包括一行,这一行只包含一个整数,

表示在规定的时间内,可以采到的草药的最大总价值。

input

100 5

77 92

22 22

29 87

50 46

99 90

output

133

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


二、完全背包

1.雏形:有N件物品和一个容量为v的背包,每个物品都有无限件可用,第i件物品体积为c[i],价值为w[i]。

求怎样能使背包的物品价值最大?

2.特点:每件物品都有无数件可用。

3.状态转移方程:

二维:F[i][v]=max{F[i-1][v-k*c[i]]+k*w[i]|0<=k*c[i]<=v}

注:

顺序:我们顺序写,这里的max中的两项就是当前状态的值,因为每种背包都是无限的。当我们把i从1到N循环时,

f[v]表示容量为v在前i种背包时所得的价值,这里我们要添加的不是前一个背包,而是当前背包。

所以我们要考虑的当然是当前状态。

4.例题

input

XXX上山去采药。XXX有一个容量为m(1<=m<=1000)的背包,

他所采集的药材的总重量不能大于背包的容量。

已知共有n(1<=n<=1000 )种药材,每种药材都有无限多,

并且知道每种药材的重量w(1<=w<=m)及价值v(1<=v<=100000),

如何选择,才能使得采到的药材的总价值最大?

第1行为两个整数m和n,分别为背包的容量及药材的种数。

第2至n+1行每行两个整数w和v,分别表示每种药材的重量及价值。

output

能采到的药材的最大总价值

input

100 5

77 92

33 50

34 60

50 46

99 161

output

161

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


三、多重背包

1.雏形:有N件物品和一个容量为v的背包,每个物品都有无限件可用,第i件物品体积为c[i],价值为w[i]。

求怎样能使背包的物品价值最大?

2.特点:第i件物品最多有n[i]件。

3.状态转移方程:

二维:F[i][v]=max{F[i-1][v-k*c[i]]+k*w[i]|0<=k<=n[i]}

四、区别

1.01背包和完全背包

01背包是顺序,完全背包是逆序。

首先想想为什么01背包中要按照v=V..0的逆序来循环。

这是因为要保证第i次循环中的状态 dp[i][v]是由状态dp[i-1][v-c[i]]递推而来。换句话说,这正是为了保证每件物品只选一次,保证在考虑“选入第i件物品”这件策略时,依据的是一个绝无已经选入第i件物品的子结果dp[i-1][v-c[i]]。

而现在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第i种物品”这种策略时,却正需要一个可能已选入第i种物品的子结果dp[i][v-c[i]],所以就可以并且必须采用v=0..V的顺序循环。这就是这个简单的程序为何成立的道理。

2.完全背包和多重背包

这两者很类似。多重背包的方程只需将完全背包问题的方程略微一改即可,因为对于第i种物品有n[i]+1种策略:取0件,取1件……取n[i]件。

部分参考http://www.cppblog.com/tanky-woo/archive/2010/07/31/121803.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: