void-man

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

题目意思给出一个整数数列,1到n,把它分为两组数,要求两组数的和相等。

根据题目,首先可以判定当1到n 的和是4的倍数或者被4整除余1的话,才可以被拆分,否则直接break

n个数的总和为sum:=n*(n+1)shr 1,当且仅当sum为偶数的时候才有解,sum为奇数时直接输出0并且退出程序;但是这样做了也还是会超时。所以要进行优化处理。经计算 只有n=4K 和n=4K-1 (K属于正整数)时才有解 不然直接输零 也不用计算了。

动态规划 设分成的子集为set1,set2,sum=(n*(n+1)div 2)div 2. 设f[i,j]表示取前i个数,使set1总数和为j的方案数.第i个数的值为i,根据是否取第i个数就有:

f[i,j]=f[i-1,j]+f[i-1,j-i]    j-i>=0 
f[i,j]=f[i-1,j] j-i<0
/*
ID: xvoid191
PROG: subset
LANG: C++
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAX 40
using namespace std;
typedef long long llong;
llong dp[MAX][1000];
int N;
int main()
{
freopen("subset.in","r",stdin);
freopen("subset.out","w",stdout);
scanf("%d",&N);
if(!(N%4==0||(N+1)%4==0)){
printf("0\n");
return 0;
}
memset(dp,0,sizeof(dp));
dp[1][1] = 1;
dp[1][0] = 1;
for(int i = 2; i <= N;i++){
for(int j = 0; j <= N*(N+1)/4 ;j++){
if(j >= i)dp[i][j] = dp[i - 1][j] + dp[i - 1][j - i];
else dp[i][j] = dp[i - 1][j];
}
}
printf("%lld\n",dp[N][N*(N+1)/4]/2);
}



posted on 2012-02-02 21:40  void-man  阅读(380)  评论(0)    收藏  举报