码迷,mamicode.com
首页 > 其他好文 > 详细

hihocoder(1038,1043) 01背包与完全背包

时间:2015-04-13 10:51:19      阅读:128      评论:0      收藏:0      [点我收藏+]

标签:

动态规划是一直感觉比较模糊的东西,虽然大致上知道是什么一回事,但是离灵活应用还差得远,但貌似比赛中动态规划的题出的特别多,这两个经典问题其实只能算是一个学习动态规划很好的模型。不过万事开头难,关键还是得静下心来多练习。

01背包的状态转移式f(i, j) = max{f(i-1, j), f(i-1, j-need[i])+value[i]}

直接按照上述的状态转移式申请二维数组进行运算,伪代码如下:

fori : 1..N  

  f(0,j) = 0

for i : 1..N

  for j : 0..M

    if(j < need(i))  f(i, j) = f(i-1, j)

    else  f(i, j) = max{f(i-1, j), f(i-1, j-need[i])+value[i]}

但是这样写,空间复杂度是非常大的,因为有一个很大的二维数组,但是仔细观察公式,或者在纸上画画格子,就会发现,每次计算所需要的只是i-1行的数据,因此,很容易想到的是可以用两行一维数组交替使用即可,但是,再仔细观察,会发现每次计算都是用的左上方的数据,这样也就是说,如果反过来计算:

for i:1..N

  for j: M..need(i)

    f(j) = max{f(j), f(j-need(i))+value(i)}

就不会覆盖“左上方”的数据,并且能顺利完成整个状态转移量的计算。

代码其实就是状态转移式了,所以说动态规划的问题,只要能列出正确的状态转移式,离AC也就不远了。

Impl:

技术分享
 1 #include <iostream>
 2 using namespace std;
 3 
 4 int main()
 5 {
 6     int N,M;
 7     cin >> N >> M;
 8     int *need = new int[N];
 9     int *value = new int[N];
10     for (int i = 0; i < N; ++i)
11         cin >> need[i] >> value[i];
12     int *dp = new int[M];
13     
14     for (int i = 0; i < M; ++i)
15         dp[i] = 0;
16     for (int i = 0; i < N; ++i)
17         for (int j = M-1; j > need[i]; j--)
18             dp[j] = max(dp[j], dp[j-need[i]]+value[i]);
19         
20     cout << dp[M-1] << endl;
21         
22         
23     delete [] need;
24     delete [] value;
25     delete [] dp;
26         
27     return 0;
28 }
View Code

 

完全背包的状态转移式f(i, j) = max{f(i-1, j), f(i, j-need[i])+value[i]}

完全在描述上就是第i的物品可以取任意次,

同样的,如果直接按照上述的状态转移式申请二维数组进行运算,伪代码如下:

fori : 1..N  

  f(0,j) = 0

for i : 1..N

  for j : 0..M

    if(j < need(i))  f(i, j) = f(i-1, j)

    else  f(i, j) = max{f(i-1, j), f(i, j-need[i])+value[i]}

明显也可以优化空间复杂度,直接从数组计算上来看,每次计算f(i,j)都需要本行左端的数据,因此相对与01背包来说,这时只需要正着算就可以了。这里其实也可以理解为,01背包中循环之所以要倒着写,就是为了要响应每个物品只能用一次这个条件,而完全背包中,物品是无限制的,因此,下一个状态必须考虑其前面的子状态,所以循环便是正着的了。

for i:1..N

  for j: need(i)..M

    f(j) = max{f(j), f(j-need(i))+value(i)}

Impl:

技术分享
 1 #include <iostream>
 2 using namespace std;
 3 
 4 int main()
 5 {
 6     int N,M;
 7     cin >> N >> M;
 8     int *need = new int[N];
 9     int *value = new int[N];
10     for (int i = 0; i < N; ++i)
11         cin >> need[i] >> value[i];
12     int *dp = new int[M];
13     
14     for (int i = 0; i < M; ++i)
15         dp[i] = 0;
16     for (int i = 0; i < N; ++i)
17         for (int j = need[i]; j < M; ++j)
18             dp[j] = max(dp[j], dp[j-need[i]]+value[i]);
19         
20     cout << dp[M-1] << endl;
21         
22         
23     delete [] need;
24     delete [] value;
25     delete [] dp;
26         
27     return 0;
28 }
View Code

 

hihocoder(1038,1043) 01背包与完全背包

标签:

原文地址:http://www.cnblogs.com/sheepsheep/p/4421545.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!