USACO 2.2 Subset Sums(subset)

        这个题是经典0-1背包问题的变形,在正整数区间[1,n]内,选择一个子集,和为n*(n+1)/4,求总共能够选择的子集数除以2。首先想到的是穷举可能的状况,可是始终超时。后来采用动态规划,用ans[i][j]表示在区间[0,i]选择一个其和为j的子集,总共可能的子集数,因而状态转移方程:ios

   if(j<i)    ans[i][j]=ans[i-1][j];
   if(j==i)  ans[i][j]=ans[i-1][j]+1;
   if(j>i)    ans[i][j]=ans[i-1][j]+ans[i-1][j-i]; spa

其中起始点a[1][1]=1,i取值范围:1~n,j取值范围:1~n*(n+1)/4。code

 

/*
ID:jzzlee1
PROG:subset
LANG:C++
Dear double_tings:
i love you.
*/
//#include<iostream>
#include<fstream>
#include<cmath>
#include<string>
#include<cstring>
#include<bitset>
using namespace std;
ifstream cin("subset.in");
ofstream cout("subset.out");
long long ans[40][40*(40+1)/2]; 
int main(){
	int n;
	cin>>n;
	int half=n*(n+1)/4;
	if(n*(n+1)%4!=0) 
	{
		cout<<0<<endl; 
		return 0;
	}
	ans[1][1] = 1;
	for(int i = 2; i <= n; i++)
		for(int j = 1; j <= half; j++)
			if(j < i)	ans[i][j] = ans[i-1][j];
			else if(j == i) ans[i][j] = ans[i-1][j]+1;
			else  ans[i][j] = ans[i-1][j] + ans[i-1][j-i]; 
    cout<<ans[n][half]/2<<endl;  
	return 0;
}
相关文章
相关标签/搜索