集合
题目描述
对于从1到N (1 <= N <= 39) 的连续整数集合,能划分成两个子集合,且保证每个集合的数字和是相等的。举个例子,如果N=3,对于{1,2,3}能划分成两个子集合,每个子集合的所有数字和是相等的:
{3} 和 {1,2}
这是唯一一种分法(交换集合位置被认为是同一种划分方案,因此不会增加划分方案总数) 如果N=7,有四种方法能划分集合{1,2,3,4,5,6,7},每一种分法的子集合各数字和是相等的:
{1,6,7} 和 {2,3,4,5} {注 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。程序不能预存结果直接输出(不能打表)。
分析:设集合中所有数总和为sum,由于要分成总和相同的两份,所以最后一份的总和一定是sum/2,可以看出当sum是奇数时一定分不成总和相同的两份,那么当sum是偶数时,每个数只有选和不选,这样问题就变成了01背包问题,f[i,j]=f[i-1,j]+f[i-1,j-i];
时间复杂度:O(n^2)
代码
const maxn=10000; var f:array[0..100,-maxn..maxn] of longint; i,j,n,s:longint; begin readln(n); s:=n*(n+1) div 2; if odd(s) then begin writeln(0); halt; end; s:=s div 2; f[0,0]:=1; for i:=1 to n do for j:=1 to s do f[i,j]:=f[i-1,j]+f[i-1,j-i]; writeln(f[n,s]); end.