1、这道题让我对DP的理解更深一层。。。原来我从未真正理解过DP。。。
2、本题给出一些数,让将数划分为两个集合,使每个集合的数之和相等,问有多少种划分方案。
3、刚开始我看数据最多39个,就想用暴搜,结果n=36就是极限了。我用了各种优化,各种剪枝,包括考虑了枚举的顺序,已经是极限了。本来还想打表水过的,结果n=39的结果怎么也出不来(大概一分钟了也出不来)。后来到网上查题解才知道用dp。。。而且暴搜的时间是指数级的!我自己想了一下dp的写法,其实不难,代码非常短,用了滚动数组,非常优美,n=39的数据很快就过了(好像是0.01s),给我留下了很深的印象。
4、看了一下官方题解,居然写得跟标程一样,囧。。。
/*
ID:mrxy564
PROG:subset
LANG:C++
*/
#include<cstdio>
using namespace std;
int n,all;
long long dp[800];
int main(){
freopen("subset.in","r",stdin);
freopen("subset.out","w",stdout);
scanf("%d",&n);
all=n*(n+1)/2;
if(all&1){
printf("0\n");
return 0;
}
else{
all/=2;
dp[0]=1;
for(int i=1;i<=n;i++)
for(int j=all;j>=i;j--)
dp[j]+=dp[j-i];
printf("%lld\n",dp[all]/2);
}
return 0;
}
官方题解:
This is a classic dynamic programming problem. Hal's solution is shown below.
/* Calculate how many two-way partitions of {1, 2, ..., N} are even splits (the sums of the elements of both partition are equal) */ #include <stdio.h> #include <string.h> #define MAXSUM 637 unsigned int numsets[637][51]; int max; unsigned int sum; main(int argc, char **argv) { int lv, lv2, lv3; int cnt; FILE *fin, *fout; fin = fopen ("subset.in", "r"); fscanf(fin, "%d", &max); fclose (fin); fout = fopen("subset.out", "w"); if ((max % 4) == 1 || (max % 4) == 2) { fprintf (stderr, "0\n"); exit(1); } sum = max * (max+1) / 4; memset(numsets, 0, sizeof(numsets[0])); numsets[0][0] = 1; for (lv = 1; lv < max; lv++) { for (lv2 = 0; lv2 <= sum; lv2++) numsets[lv2][lv] = numsets[lv2][lv-1]; for (lv2 = 0; lv2 <= sum-lv; lv2++) numsets[lv2+lv][lv] += numsets[lv2][lv-1]; } fprintf (fout, "%u\n", numsets[sum][max-1]); fclose (fout); exit (0); }
and here's an even more concise solution from Nick Tomitov of Bulgaria:
#include <fstream> using namespace std; const unsigned int MAX_SUM = 1024; int n; unsigned long long int dyn[MAX_SUM]; ifstream fin ("subset.in"); ofstream fout ("subset.out"); int main() { fin >> n; fin.close(); int s = n*(n+1); if (s % 4) { fout << 0 << endl; fout.close (); return ; } s /= 4; int i, j; dyn [0] = 1; for (i = 1; i <= n; i++) for (j = s; j >= i; j--) dyn[j] += dyn[j-i]; fout << (dyn[s]/2) << endl; fout.close(); return 0; }