计蒜客——等和的分隔子集

原题链接: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;
    }
}

 

posted @ 2018-06-07 23:37  喝醉的香锅锅  阅读(367)  评论(0编辑  收藏  举报