等和的分割子集
阿新 • • 發佈:2018-12-30
曉萌希望將 11 到 NN 的連續整陣列成的集合劃分成兩個子集合,且保證每個集合的數字和是相等。例如,對於 N=3,對應的集合{1,2,3} 能被劃分成{3} 和 {1,2} 兩個子集合.
這兩個子集合中元素分別的和是相等的。
對於N=3 ,我們只有一種劃分方法,而對於 N=7 時,我們將有 4 種劃分的方案。
輸入格式
輸入包括一行,僅一個整數,表示 N(1≤N≤39)的值。
輸出格式
輸出包括一行,僅一個整數,曉萌可以劃分對應 N 的集合的方案的個數。當沒法劃分時,輸出 0。
樣例輸入
7
樣例輸出
4
最近玩遞迴玩的有點上癮,看到這個題,第一想法就是遞迴,簡單粗暴,然後果斷TLE。。。無奈之下,試試剛剛get的左神的大套路,居然特麼,,,就這樣把遞迴改成動規過了。。。
遞迴程式碼如下:
void fun(int i,int sum){ if(sum==aim/2){ cnt++; return; } if(sum>aim/2) return ; for(int j = i+1;j < n;j++){ fun(j,sum+j); } }
1,考慮動規維度: 由於變數是兩個,那麼動規的表當然就是二維的啦。
2,動規初始值:動規的初始值就是遞迴的出口,對於本題就是dp[i][aim/2]=1;
3,解得位置:遞迴第一次傳的值是啥,解的位置就是啥啦,遞迴用的fun(0,0),解就是dp[0][0]了,最後注意本題重複計算了,需要除以2.
4,轉移方程:動規的核心,這特麼的會了,code就輕鬆加愉快了。動規的轉移方程就是遞迴的遞迴體,不過需要稍微修改一下。比如說遞迴求y需要x,那麼動規則是知道x求y,逆向思維一下,轉移方程就get了。
附上完整程式碼:
#include<bits/stdc++.h> using namespace std; int cnt=0,n,aim=0; long long dp[40][800]={0}; int main(){ cin>>n; for(int i=1;i<=n;i++){ aim+=i; } if(aim%2)cout<<"0"<<endl; else{ for(int i=1;i<=n;i++){ dp[i][aim/2] = 1; } for(int i=aim/2;i>=0;i--){ for(int j=0;j<=n;j++){ for(int k=j+1;k<=n;k++){ if(i>=k) dp[j][i-k] += dp[k][i]; } } } cout<<dp[0][0]/2<<endl; } return 0; }