对于由从1到N (1 <= N <= 39)这N个连续的整数组成的集合来说,我们有时可以将集合分成两个部分和相同的子集合。 例如,N=3时,可以将集合{1, 2, 3} 分为{1,2}和{3}。此时称有一种方式(即与顺序无关)。 N=7时,共有四种方式可以将集合{1, 2, 3, ..., 7} 分为两个部分和相同的子集合:(建议用动态规划算法)
{1,6,7} 和 {2,3,4,5}
{2,5,7} 和 {1,3,4,6}
{3,4,7} 和 {1,2,5,6}
{1,2,4,7} 和 {3,5,6}
输入:程序从标准输入读入数据,只有一组测试用例。如上所述的N。 输出:方式数。若不存在这样的拆分,则输出0。
测试用例:
输入:
7
输出:
4
方法一用的是一个一维的动规
#include<stdio.h>
#include<string.h>
int main()
{
long long int n,dp[2000],i,j,num;
scanf("%d",&n);
memset(dp,0,sizeof(dp));
num=n*(n+1);
if (num%4!=0) //前n项和必须为偶数才能划分为两个子集
printf("0\n");
else
{
dp[0]=1;
num=num/4;
for (i=1;i<=n;i++) //当选取的数为i时
{
for (j=num;j>=i;j--) //更新一遍组成和为j的组数
dp[j]=dp[j-i]+dp[j];
}
printf("%d\n",dp[num]/2);
}
}
方法二是二维的动规
#include<stdio.h>
#include<string.h>
int dp[2000][2000]={0};
int main()
{
long long int n,i,j,num;
scanf("%d",&n);
memset(dp,0,sizeof(dp));
num=n*(n+1);
if (num%4!=0) //前n项和必须为偶数才能划分为两个子集
printf("0\n");
else
{
dp[0][0]=1;
num=num/4;
for (i=1;i<=n;i++)
{
for (j=1;j<=num;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("%d\n",dp[n][num]);
}
}