您的位置:首页 > 编程语言 > C语言/C++

动态规划DP入门 0-1背包

2017-11-01 12:54 363 查看
人生第一篇博客……写个简单点的……

作为一个炒鸡蒟蒻,在第一次看到0-1背包问题时,我就一个想法:

贪心。

然后我就这么干了……

预处理伪代码如下:

for(int i=1;i<=n;i++)
{
cin >> w[i] >> c[i];
t[i]=c[i]/w[i];
}


也就是求利润率之类的……

但是,这么写过的童鞋都知道,这样肯定是不能A题的。

于是,我们就需要一种高级的算法——

动态规划~

然后我就一脸mengbi地听着老师打着EXCEL说着什么无后效性什么转移方程

然后我就来解释一下吧……

无后效性:指现在对数据做的操作不会影响以后的操作

举个栗子:

比如方格取数这道题目

虽然这道题目的标签有一个DP……作为一个不会dp的人一眼看去肯定是做两遍

那么就有问题了:把一个格子的值去掉会对另一个人的值影响,所以这道题用非dp做法是有后效性

所以我们要用DP做 当然这不是我们研究的重点

接下来我们研究0-1背包

其实我一直都不太理解0-1是什么意思 大概是从无到有的意思吧

例题见 采药

于是我们又要带进状态状态转移方程这两个概念了

状态:指的是程序进行到某个阶段时的值(好草率啊)

状态转移方程:由一个状态转到另一个状态的方程

DP还有一个特点,就是将大问题分解成小问题,有点类似于分治

这里就要用到一种强大而平常的工具:EXCEL

以采药为例:

我们设 f[i] 表示我们用了 i 的时间所能采到的最大价值

设计一组输入样例:

5 3
3 2
1 4
4 5


然后上EXCEL:

设横轴为时间

得到这样一张表:



然后我们针对每一时间,得到能够采到的最大价值。

然后填完这张表。

我们先把转移方程打出来,配合表理解:

f[j]=max(f[j],f[j−w[i]]+c[i]) w是时间,c是价值

然后把表填起来:



然后就可以得出解了,答案在 f[v] 的位置

转移方程的理解:

在当前时间下,可以做两种决策:

- 采这种药,可以发现价值为 f[j−w[i]]+c[i]

- 不采这种药,价值为 f[j]

在这两个里找出最大的,就可以得出方程了

附代码:

C++:

#include<cstdio>
#include<algorithm>
using namespace std;
struct bag
{
int g,p;
}t[100005];
int sum[100005];
int main()
{
int w,n,i,j;
scanf("%d%d",&w,&n);
for(i=1;i<=n;i++) scanf("%d%d",&t[i].g,&t[i].p);
for(i=n;i>=1;i--)
for(j=w;j>=t[i].g;j--)sum[j]=max(sum[jt[i].g]+t[i].p,sum[j]);
printf("%d",sum[w]);
return 0;
}


Pascal:

var i,j,n,v:integer;
f:array[1..2005] of integer;
w,p:array[1..2005] of integer;
begin
readln(v,n);
for i:=1 to n do readln(w[i],p[i]);
for i:=1 to n do
begin
for j:=v downto w[i] do
begin
if f[j]<f[j-w[i]]+p[i] then f[j]:=f[j-w[i]]+p[i];
end;
end;
writeln(f[v]);
end.


写的不好,请多吐槽

原创 By Venus

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息