今天看了一天的动态规划,其他主要还是背包问题了(01背包,完全背包,多重背包)
核心就是状态转移方程了,在说下几个重要的问题:
1.01背包开始为什么是从V到0?
因为要比较f[i-1][j]和f[i-1][j-w[i]]+v[i].如果从0到v,则j-w[i]是先算的,所以f[j]就是根据f[j-w[i]]算出来的。也就是说,要注意因果关系。
2.如果多重背包和完全背包转换成01背包,则也需要从v-0循环
3.完全背包和多重背包相似,但是区别于01背包。01背包考虑的是放于不放,而完全背包和多重背包考虑的是放0,1,2……个(或者有限个)。
所以完全背包和多重背包,需要写一个求序列最大值的函数。而最后是把那个最大值赋给f[i][j].
根据以上分析,总结一下背包问题要做的事:
1.分析状态转移方程,这个很基本。
2.把f[i][j]这个数组全部初始化为0.
3.要把f[0][c]这个一行给初始化了,值都是从V-0的值。
4.开始根据状态转移方程来写循环。
以下是我写的完全背包例程:
#include <stdio.h> #include <iostream> #include <stack> #include <string> #include <vector> #include <list> #include <algorithm> #include <deque> using namespace std; int a[10][100]; int n = 0, c = 0; int max(int a, int b) { return a >= b ? a : b; } int max_data(vector<int> m) { int max = 0; for (int i = 0; i < m.size(); i++) { if (m[i] >= max) { max = m[i]; } } return max; } void fun(vector<int> w, vector<int> v, vector<int> num) { for (int j = c; j >= 0; j--) { for (int k = 0; k <= c/w[0]; k++) { if (j >= k*w[0]) { a[0][j] = k*v[0]; } } } for (int i = 1; i < n; i++) { for (int j = c; j >= 0; j--) { vector<int> tmp; for (int k = 0; k <= c/w[i]; k++) { if (j >= k*w[i]) { tmp.push_back(a[i - 1][j - k*w[i]] + k*v[i]); } } a[i][j] = max_data(tmp); } } } int main() { while (cin >> c>>n) { vector<int> w, v, num; for (int i = 0; i < n; i++) { int tmp1, tmp2, tmp3; cin >> tmp1 >> tmp2 >> tmp3; w.push_back(tmp1); v.push_back(tmp2); num.push_back(tmp3); } fun(w, v, num); cout << a[n-1][c] << endl; } return 0; }
最后再结合今天做的称砝码问题:
有一组砝码,重量互不相等,分别为m1、m2、m3……mn;它们可取的最大数量分别为x1、x2、x3……xn。
现要用这些砝码去称物体的重量,问能称出多少种不同的重量。
Input
测试数据第一行一个整数n(n<=10),表示有多种不同的砝码;
第二行n个整数(中间用空格分隔),m1、m2、m3……mn,分别表示n个砝码的重量;(1<=mi<=20)
第三行n个整数(中间用空格分隔),x1、x2、x3……xn,分别表示n个砝码可取的最大数量。(1<=xi<=20)
Output
每组数据输出仅一行,一个整数,表示利用给定的砝码可以称出的不同的重量数。
注:包括0。
Sample Input
2
1 2
2 1
其实这个问题,就是背包问题。
总的砝码质量c我们是可以知道的,题目就变成了,有一个可以装下总质量c砝码的背包。
现在有n组砝码w[i],每组有num[i]个,可以放可以不放。这就是多重背包。
我们在动态规划的过程中,会把所有的可能都列出来。
最后再对列出的所有结果去重就可以了。
#include <stdio.h> #include <iostream> #include <stack> #include <string> #include <vector> #include <list> #include <algorithm> #include <deque> using namespace std; int a[100][100]; int n = 0, c = 0; int max(int a, int b) { return a >= b ? a : b; } int max_data(vector<int> m) { int max = 0; for (int i = 0; i < m.size(); i++) { if (m[i] >= max) { max = m[i]; } } return max; } void fun(vector<int> w,vector<int> num) { for (int j = c; j >= 0; j--) { for (int k = 0; k <= num[0]; k++) { if (j >= k*w[0]) { a[0][j] = k*w[0]; } } } for (int i = 1; i < n; i++) { for (int j = c; j >= 0; j--) { vector<int> tmp; for (int k = 0; k <= num[i]; k++) { if (j >= k*w[i]) { tmp.push_back(a[i - 1][j - k*w[i]] + k*w[i]); } } a[i][j] = max_data(tmp); } } } int main() { while (cin >>n) { vector<int> w,num; for (int i = 0; i < n; i++) { int tmp1; cin >> tmp1; w.push_back(tmp1); } for (int i = 0; i < n; i++) { int tmp1; cin >> tmp1; num.push_back(tmp1); } for (int i = 0; i < n; i++) { c += w[i] * num[i]; } fun(w,num); vector<int> res; for (int i = 0; i < 100; i++) { for (int j = 0; j < 100; j++) { res.push_back(a[i][j]); } } sort(res.begin(), res.end()); res.erase(unique(res.begin(), res.end()), res.end()); cout << res.size() << endl; } return 0; }