Tony's Log

Algorithms, Distributed System, Machine Learning

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

HihoCoder上有两道背包问题的problem,

http://hihocoder.com/problemset/problem/1038 (01背包)

#include <cmath>
#include <cstdio>
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;

int main() 
{
    //    Get input
    int n, m; cin >> n >> m;
    vector<int> need;
    vector<int> value;

    int tmp = n;
    while (tmp--)
    {
        int vneed, vvalue; 
        cin >> vneed >> vvalue;
        need.push_back(vneed);
        value.push_back(vvalue);
    }

    //    DP: dp[j] is max value by using up to j tickets
    vector<int> dp(m + 1, 0);
    for (int i = 0; i < n; i ++)
        for (int j = m; j > need[i]; j --) // note the dependency order
            dp[j] = std::max(dp[j], dp[j - need[i]] + value[i]);
    cout << dp[m] << endl;

    return 0;
}

 

http://hihocoder.com/problemset/problem/1043 (完全背包)

#include <cmath>
#include <cstdio>
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;

int main() 
{
    //    Get input
    int n, m; cin >> n >> m;
    vector<int> need;
    vector<int> value;

    int tmp = n;
    while (tmp--)
    {
        int vneed, vvalue; 
        cin >> vneed >> vvalue;
        need.push_back(vneed);
        value.push_back(vvalue);
    }

    //    DP: dp[j] is max value by using up to j tickets
    vector<int> dp(m + 1, 0);
    for (int i = 0; i < n; i ++)
        for (int j = 0; j <= m; j ++)
            if (j > need[i])
                dp[j] = std::max(dp[j], dp[j - need[i]] + value[i]);
    cout << dp[m] << endl;

    return 0;
}

可以看到两者之间只有微妙的不同,目前搜到解释的最清楚的还是崔添翼的“背包九讲”(http://love-oriented.com/pack/P02.html)

你会发现,这个伪代码与P01的伪代码只有v的循环次序不同而已。为什么这样一改就可行呢?首先想想为什么P01中要按照v=V..0的逆序来循环。这是因为要保证第i次循环中的状态f[i][v]是由状态f[i-1][v-c[i]]递推而来。换句话说,这正是为了保证每件物品只选一次,保证在考虑“选入第i件物品”这件策略时,依据的是一个绝无已经选入第i件物品的子结果f[i-1][v-c[i]]。而现在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第i种物品”这种策略时,却正需要一个可能已选入第i种物品的子结果f[i][v-c[i]],所以就可以并且必须采用v=0..V的顺序循环。这就是这个简单的程序为何成立的道理。

简单直接,大师级别的理解和讲解

posted on 2015-04-03 05:05  Tonix  阅读(224)  评论(0编辑  收藏  举报