【动态规划】01背包问题

  今天小编闲的不行,就打开洛谷,随便一打卡就是大吉,还宜刷题。

  正巧上午比赛时有一道背包问题,于是小编默默打开试炼场,瞅准了背包问题(别问我为什么),正所谓自知者明,小编也知道自己很水(建议看背包九讲),于是挑了三道题:

  在写之前总得知道什么是背包问题吧,背包问题一般长这样:

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

  那么如何解这种题目呢,先定义一个数组f[i][j]为当一共有i件物品,背包容量为j时的最大价值。然后就要找状态转移方程了,小编以前总认为状态转移方程难写,但是只要一项一项列出来就好了。对于每一个物品,无非就两种可能:要么选,要么不选。那么先看选,凡是总有回报和代价把,选了之后代价是什么呢?想一想,是不是选了之后背包剩余容量就减少了;那么回报呢?当然是价值增加了呗。但是不选就不一样了,应为啥也没干,最大价值和之前一样,不增不减。这不就出来了嘛,两种情况如下:

  •   选:f[i][j]=f[i-1][j-w[i]]+value[i];
  •        不选:f[i][j]=f[i-1][j];

  因为题目求的是最大价值,所以两者中取大的就可以了,得到以下状态转移方程:

  f[i][j]=max(f[i-1][j-w[i]]+value[i],f[i-1][j]);

  有没有发现什么,我们用了二维数组,虽然时间上已经难以优化,但是空间上还是可以优化成一维数组的,只要同时去掉i的那一个维度就可以了,因为二维数组有太多不需要一直记录的,直接不断更新一维数组(滚动数组的方式)就可以了,更改如下:

  f[j]=max(f[j-w[i]]+value[i],f[j]);

  具体怎么实现,看几道吧。

  先看第一道:

 

  这道题处于秒杀的行列,直接用刚才的方法,把钱数看成是容量,把重要程度*价格看成是价值就好了,直接写就行,代码奉上:

 1 #include<iostream>
 2 using namespace std;
 3 long long cost[30000],w[30000],f[30000],ans;
 4 int main()
 5 {
 6     long long n,m;
 7     cin>>n>>m;
 8     for(int i=1;i<=m;i++)
 9     cin>>cost[i]>>w[i];
10     for(int i=1;i<=m;i++)
11     for(int j=n;j>=cost[i];j--)
12     {
13         if(j>=w[i])
14         f[j]=max(f[j],f[j-cost[i]]+w[i]*cost[i]);
15     }
16     cout<<f[n];
17     return 0;
18 }

先来看一下采药,比上面的还简单:

  把时间看成容量,就可以了,代码献上:

 1 #include<iostream>
 2 using namespace std;
 3 int t,m,w[1000],cost[1000],f[1000];
 4 int main()
 5 {
 6     cin>>t>>m;
 7     for(int i=1;i<=m;i++)
 8     cin>>w[i]>>cost[i];
 9     for(int i=1;i<=m;i++)
10     for(int j=t;j>=w[i];j--)
11     {
12         f[j]=max(f[j],f[j-w[i]]+cost[i]);
13     }
14     cout<<f[t];
15     
16     return 0;
17 }

最后来看小A点菜:

  这道题乍一看没思路,还按照刚才的思路:要么吃,要么不吃,吃有什么代价,什么回报呢?钱变少了,方案数变多了呗;不吃呢?还是原来的方案数。这样两种情况就出来了:

  •   f[j-cost[i]];
  •        f[j]

   【注意】情况有变,这一次就不那么简单了,因为选和不选是两种不同的方案数,题目求的是一共的方案数,所以不是max,不是min,而是+。

  归根结底长这样:f[j]=f[j]+f[j-cost[i]];

   这样代码就出来了,代码呈上:

 1 #include<iostream>
 2 using namespace std;
 3 int n,m,cost[100000],f[10000];
 4 int main()
 5 {
 6     cin>>n>>m;
 7     for(int i=1;i<=n;i++)
 8     cin>>cost[i];
 9     f[0]=1;
10     for(int i=1;i<=n;i++)
11     for(int j=m;j>=cost[i];j--)
12     f[j]=f[j]+f[j-cost[i]];
13     cout<<f[m];
14     return 0;
15 }
posted @ 2019-03-24 19:09  c1714-gzr  阅读(848)  评论(0编辑  收藏  举报