P1466 集合 Subset Sums(01背包求填充方案数)

题目链接:https://www.luogu.org/problem/show?pid=1466

题目大意:对于从1到N (1 <= N <= 39) 的连续整数集合,能划分成两个子集合,且保证每个集合的数字和是相等的。举个例子,如果N=3,对于{1,2,3}能划分成两个子集合,每个子集合的所有数字和是相等的:{3} 和 {1,2}.

解题思路:01背包问题,设sum是1~n之和,其实就是求用数字1~n凑出sum/2的方案数(每个数字只能用一次),概括为以下几点:

     ①sum为奇数不能平分,直接输出0。

     ②求出来的方案数要除2,因为如果有一组能平分,那么凑出sum/2的方案数就是2。

     ③状态转移方程:dp[j]=dp[j]+dp[j-i]。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 const int N=1e4+5;
 6 
 7 long long dp[N];
 8 
 9 int main(){
10     int n;
11     while(~scanf("%d",&n)){
12         memset(dp,0,sizeof(dp));
13         int sum=(1+n)*n/2;
14         if(sum%2==1)
15             puts("0");
16         else{
17             sum/=2;
18             dp[0]=1;
19             for(int i=1;i<=n;i++){
20                 for(int j=sum;j>=0;j--){
21                     if(j>=i)
22                         dp[j]+=dp[j-i];
23                 }
24             }
25             printf("%lld
",dp[sum]/2);
26         }
27     } 
28     return 0;
29 }
原文地址:https://www.cnblogs.com/fu3638/p/7777325.html