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的顺序循环。这就是这个简单的程序为何成立的道理。
简单直接,大师级别的理解和讲解