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

人生第一篇博客……写个简单点的……
作为一个炒鸡蒟蒻,在第一次看到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[jw[i]]+c[i]) w是时间,c是价值
然后把表填起来:
这里写图片描述
然后就可以得出解了,答案在 f[v] 的位置
转移方程的理解:

在当前时间下,可以做两种决策:
- 采这种药,可以发现价值为 f[jw[i]]+c[i]
- 不采这种药,价值为 f[j]

在这两个里找出最大的,就可以得出方程了
附代码:
C++:

#include
#include
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]then f[j]:=f[j-w[i]]+p[i];
end;
end;
writeln(f[v]);
end.

写的不好,请多吐槽

原创 By Venus

你可能感兴趣的:(c++)