原题链接:https://nanti.jisuanke.com/t/28
题目
晓萌希望将1到N的连续整数组成的集合划分成两个子集合,且保证每个集合的数字和是相等。例如,对于N=3,对应的集合{1,2,3}能被划分成{3} 和 {1,2}两个子集合.
这两个子集合中元素分别的和是相等的。
对于N=3,我们只有一种划分方法,而对于N=7时,我们将有4种划分的方案。
输入包括一行,仅一个整数,表示N的值(1≤N≤39)。
输出包括一行,仅一个整数,晓萌可以划分对应N的集合的方案的个数。当没发划分时,输出0。
样例输入
7
样例输出
4
/* * 思路 * 1、总和为奇数,那么划分的方案数为0 * 2、总和为偶数,假设每部分的和为m。直接暴力枚举:从1~n,看能否凑成需要的和m,当这个数小于m的时候,才有可能 * 是和的一部分,那么就两种情况,递归求解。 * 3、因为在两种情况下存在重复计算的情况,就使用动态规划的思想用一个数组,把计算过的保存下来。 * 4、最后的方案数会比较大,使用long型。 * * */ import java.util.*; public class 等和的分隔子集 { /*n最大为39,所以每一部分的总和最大为390. * 初始为0:表示还没有计算过。 * -1:表示当前情况的方案数为0 * 整数:表示当前情况的方案值。 * */ private static long[][] done=new long[391][391]; public static void main(String[] args) { int n; Scanner in=new Scanner(System.in); n=in.nextInt(); System.out.println(solve(n)); } static long solve(int n){ int count=n*(n+1)/2; if(count%2==1){ return 0; } count/=2; return isOk(n,count,1)/2; } static long isOk(int scope,int currentCount,int index){ if(index>scope||currentCount<index){ done[currentCount][index]=-1;//表示无法获得 return 0; } //因为是从小到大的,所以当前找到了,说明后面肯定没有了,返回1. if(currentCount==index){ return 1; } long a=0; if(done[currentCount][index+1]==0){ a=isOk(scope,currentCount,index+1); done[currentCount][index+1]=(a==0?-1:a); }else{ a=done[currentCount][index+1]==-1?0:done[currentCount][index+1]; } long b; if(done[currentCount-index][index+1]==0){ b=isOk(scope,currentCount-index,index+1); done[currentCount-index][index+1]=(b==0?-1:b); }else{ b=done[currentCount-index][index+1]==-1?0:done[currentCount-index][index+1]; } return a+b; } }