题目链接:http://poj.org/problem?id=1837
使用迭代器对STL容器进行遍历的方法:
for(set<int>::iterator it = check.begin(); it != check.end(); it++)
{
//...*it
}
本题
a[]存挂钩位置
b[]存物品质量
把挂在天平左边的物品的质量视为负数 反之为正数
总质量的极限为20件重25的物品都挂在15的天平挂钩处 即7500
dp[i][j]表示前i件物品总质量为(j-10000)时的挂法总数【数组下标不能为负 所以整体往右移10000】
前i件的状态至于前i-1件有关 所以用滚动数组来作dp
裸的dp思想如下:
memset(dp, 0, sizeof(dp));//初始化
dp[0][10000] = 0;//初始条件
for i = 0...g
for k = 0...20000
if dp[cur][k] != 0 //保证下面的for循环中 dp数组的第二维的下标不为负数
for j = 0...c
dp[i][k + b[i]*a[j]] += dp[i-1][k];//把重b[i]的物品放a[j]处后 用原状态dp[i-1][k]的值来不断更新现状态
以上过程稍加改动即变为滚动数组实现
复杂度:20 * 30 * 20000 约10^7
不同于许多别人的博客
个人认为这只是一道“类01背包”的问题 而不像别人所说的“就是01背包”
之前对背包问题的理解有误
看了背包九讲的目录之后才发现
“每种物品最多只能放一次”就可以往01背包想了
个人觉得
背包问题不仅旨在解决求最大价值的问题
它更广泛的意义在于 为关于“选物品”之类的问题提供了一种合适的操作模式
#include <cstdio> #include <cstdlib> #include <ctime> #include <iostream> #include <cmath> #include <cstring> #include <algorithm> #include <stack> #include <set> #include <queue> #include <vector> using namespace std; const int maxn = 25; const int maxm = 20000; int dp[2][maxm]; int a[maxn]; int b[maxn]; int main() { //freopen("in.txt", "r", stdin); int c, g; while(scanf("%d%d", &c, &g) == 2) { for(int i = 0; i < c; i++) scanf("%d", &a[i]); for(int i = 0; i < g; i++) scanf("%d", &b[i]); int cur = 0; dp[cur][10000] = 1; for(int i = 0; i < g; i++) { memset(dp[cur^1], 0, sizeof(dp[cur])); for(int t = 0; t < 20000; t++) { if(dp[cur][t]) { for(int j = 0; j < c; j++) { int tmp = t + b[i]*a[j]; dp[cur^1][tmp] += dp[cur][t]; } } } cur = cur ^ 1; } printf("%d\n", dp[cur][10000]); } return 0; }
最后我想吐槽一个事
stl要慎用
本来想着在枚举20000个总质量的时候用set记录出现过的总质量 来做个优化
没想到时间反而变成原来的50倍!
感觉stl在写大模拟的时候好用
然后像这种题还是少用吧
上面的代码16MS 下面的代码750MS
#include <cstdio> #include <cstdlib> #include <ctime> #include <iostream> #include <cmath> #include <cstring> #include <algorithm> #include <stack> #include <set> #include <queue> #include <vector> using namespace std; const int maxn = 25; const int maxm = 20000; int dp[2][maxm]; int a[maxn]; int b[maxn]; set<int> check[2]; int main() { //freopen("in.txt", "r", stdin); int c, g; while(scanf("%d%d", &c, &g) == 2) { check[0].clear(); check[1].clear(); for(int i = 0; i < c; i++) scanf("%d", &a[i]); for(int i = 0; i < g; i++) scanf("%d", &b[i]); int cur = 0; dp[cur][10000] = 1; check[cur].insert(10000); for(int i = 0; i < g; i++) { memset(dp[cur^1], 0, sizeof(dp[cur])); for(set<int>::iterator it = check[cur].begin(); it != check[cur].end(); it++) { for(int j = 0; j < c; j++) { int tmp = *it + b[i]*a[j]; dp[cur^1][tmp] += dp[cur][*it]; check[cur^1].insert(tmp); } } check[cur].clear(); cur = cur ^ 1; } printf("%d\n", dp[cur][10000]); } return 0; }