USACO 2.2 Subset Sums 集合

题目大意 


给出一个N,问有多少种方案,使集合{1.2.3……N}分成两个元素和相同的子集。例如3有一种,{1,2} 和 {3}。

样例输入&输出


sample input

7

sample output

4

分析&反思


上来就准备dfs,很快敲完,很快超时。dfs最近写多,避免惯性啊。

此题用动归,如同数字三角形。

用 f [ i ] [ j ] 表示前 i 个数字中取出一个和为 j 的子集有几种方案。

转移方程:

f [ i ] [ j ] = f [ i - 1 ] [ j ] + f [ i - 1 ] [ j - i ]  ( j - i  >= 0 )(表示不拿这个数 和 拿这个数的方案的和,所以保证拿了这个数不会超 j )

f [ i ] [ j ] = f [ i - 1 ] [ j ] ( j - i < 0)(拿这个数会超 j ,所以直接从前面继承)

另外这题的 f 一开始用的 int ,结果不够,改成 long long

代码


#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

long long n, hsum, f[50][5000];

/*void dfs(int s, int y) {
	if(y == hsum) {
		ans++;
		return;
	}
	for(int i = s+1; i <= n; i++) {
		if(y+i > hsum) break;
		dfs(i, y+i);
	}
	return;
}*/

int main() {
	
	freopen("subset.in", "r", stdin);
	freopen("subset.out", "w", stdout);
	
	cin >> n;
	
	int sum = (1+n) * n;
	sum /= 2;
	
	if(sum%2) {
		cout << "0" << endl;
		return 0;
	}
	
	hsum = (int)sum / 2;
	
	//dfs(0, 0);
	
	f[1][0] = f[1][1] = 1; 
	//对于前1个数,取出 和为1 和 和为0 的1集合的方案都是1; 
	
	for(int i = 2; i <= n; i++)
	for(int j = 0; j <= hsum; j++) {
		if(j-i < 0) f[i][j] = f[i-1][j];
		else f[i][j] = f[i-1][j] + f[i-1][j-i];
	}
	
	cout << f[n][hsum]/2 << endl;
	
	return 0;
}

备注


抓点紧了

猜你喜欢

转载自blog.csdn.net/DWAE86/article/details/81325093
2.2
今日推荐