USACO - 2.2 Subset Sums(DP)

题目链接:http://train.usaco.org/usacoprob2?a=ScFaavqnaPI&S=subset

/*
ID: 1590291
TASK: subset
LANG: C++
*/
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
/****************************************************************************************************************
            题意:对于从1到N (1 <= N <= 39) 的连续整数集合,能划分成两个子集合,且保证每个集合的数字和是相等
                  的。举个例子,如果N=3,对于{1,2,3}能划分成两个子集合,每个子集合的所有数字和是相等的:
                  求所有的分类个数,没有则输出0
            思路:
            1,动态规划 设分成的子集为set1,set2,sum=n*(n+1)/2.
            2,sum为奇数时不可能分成两个相同的,输出0
            2,设f[i,j]表示取前i个数,使set1总数和为j的方案数.第i个数的值为i,根据是否取第i个数就有:
                f[i,j]=f[i-1,j]+f[i-1,j-i]    j-i>=0
                f[i,j]=f[i-1,j]               j-i<0
                注意:(i >=1 && i <= n; j>=1 && j <= sum/2)
****************************************************************************************************************/
int dp[45][810];
int main()
{
    ifstream fin("subset.in");
    ofstream fout("subset.out");

    int n;
    while(fin>>n)
    {
        memset(dp,0,sizeof(dp));
        dp[1][0]=1;
        dp[1][1]=1;

        int sum=(1+n)*n/2;
        if(sum%2){      //如果和为奇数,当然不能划分成两个相等的
            fout<<"0"<<endl;
            continue;
        }
        sum/=2;
        for(int i = 2;i <= n;i ++){
            for(int j = 2;j <= sum;j ++){
                if(j >= i)
                    dp[i][j]=dp[i-1][j-i]+dp[i-1][j];
                else
                    dp[i][j]=dp[i-1][j];
            }
        }
        fout<<dp[n][sum]<<endl;
    }
    return 0;
}



 

posted on 2016-05-04 22:16  Jstyle  阅读(121)  评论(0编辑  收藏  举报

导航