这道题第一个想到的是采用DFS,果不其然倒在了超时下。苦思之后无解,就搜索了一下这道题的题解,发现大家都提示说要用动态规划来做。
最终采用了一维的DP。问题的关键是,建立一个数组,这个数组存放每种背包容量的数量。
比如说{1,2,3}这个组合,由于我们的目标容量是3,所以需要存放加起来为0、1、2、3这四种容量的组合数量。下面的表格是一个示例,其中第一列是容量,作为数组的标号,第二列是这种容量的数目,作为数组的值,第三列是具体的组合。
V | N | |
0 | 1 | {} |
1 | 1 | {1} |
2 | 1 | {2} |
3 | 2 | {1,2}, {3} |
这是一道典型的01背包的题目,所以就直接贴上代码了:
这边还有个暗坑,组合数量可能超过int的范围,图省事我就改成用unsigned long型存放了。
#include <iostream>
#include <fstream>
using namespace std;
const int MAXN = 39;
int N;
int t;
unsigned long f[MAXN*MAXN];
int main()
{
ifstream fin ("subset.in");
ofstream fout ("subset.out");
int i, j;
fin >> N;
t = (1+N)*N;
if (t % 4) {
fout << 0 << endl;
return 0;
}
t /= 4;
f[0] = 1;
for (i = 1; i <= N; i++)<span style="white-space:pre"> </span>//i为物品重量
for (j = t; j >= i; j--)<span style="white-space:pre"> </span>//j为背包容量
f[j] += f[j-i];
fout << f[t]/2 << endl;
return 0;
}
看了一下官方解,官方给出了二维和一维这两种解法,逻辑很清晰,很值得学习。
闲话时间。做了这道题之后,发现自己对一些经典的——比如这次的动态规划——算法不是很熟悉。如果接下来有时间的话,可能会写些关于背包问题和动态规划的理解吧。