Subset Sums
题目如下:
对于从1到N的连续整数集合,能划分成两个子集合,且保证每个集合的数字和是相等的。
举个例子,如果N=3,对于{1,2,3}能划分成两个子集合,他们每个的所有数字和是相等的:
{3}and {1,2}
这是唯一一种分发(交换集合位置被认为是同一种划分方案,因此不会增加划分方案总数)
如果N=7,有四种方法能划分集合{1,2,3,4,5,6,7},每一种分发的子集合各数字和是相等的:
{1,6,7} and {2,3,4,5} {注 1+6+7=2+3+4+5}
{2,5,7} and {1,3,4,6}
{3,4,7} and {1,2,5,6}
{1,2,4,7} and {3,5,6}
给出N,你的程序应该输出划分方案总数,如果不存在这样的划分方案,则输出0。程序不能预存结果直接输出。
思路:
用动态规划的方法,题目要求可以转化成求对于最大为N的连续整数,和为(N+1)*N/4的方法数。
T(N,(N+1)*N/4)=T(N-1, (N+1)*N/4-N)+T(N-1, (N+1)*N/4)
最终的结果输出时除以二即可
还有一点就是如果数字之和为奇数,本就不可能有解,可以直接判断
#include<iostream>
#include<string.h>
using namespace std;
int N;
int ** matrix;
int ** flag;
int dfs(int N,int sum)
{
if(sum<0||N==0)
{
return 0;
}
if(sum>(((N+1)*N)>>1))
{
return 0;
}
if(sum==(((N+1)*N)>>1)||sum==0||sum==1)
{
return 1;
}
if(flag[N][sum])
{
return matrix[N][sum];
}
matrix[N][sum]=dfs(N-1,sum-N)+dfs(N-1,sum);
// cerr<<N<<' '<<sum<<' '<<matrix[N][sum]<<endl;
flag[N][sum]=1;
return matrix[N][sum];
}
int main()
{
cin>>N;
if((((N+1)*N)>>1)%2)
{
cout<<"0"<<endl;
return 0;
}
int sum=(((N+1)*N)>>2);
matrix=new int *[N+1];
flag=new int *[N+1];
for(int i=0;i<=N;i++)
{
matrix[i]=new int[sum+1];
flag[i]=new int[sum+1];
memset(matrix[i],0,sizeof(int)*(sum+1));
memset(flag[i],0,sizeof(int)*(sum+1));
}
cout<<dfs(N,sum)/2;
}