这个题是经典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; }