1. 程式人生 > >等和的分割子集

等和的分割子集

曉萌希望將 11NN 的連續整陣列成的集合劃分成兩個子集合,且保證每個集合的數字和是相等。例如,對於 N=3,對應的集合{1,2,3} 能被劃分成{3}{1,2} 兩個子集合.

這兩個子集合中元素分別的和是相等的。

對於N=3 ,我們只有一種劃分方法,而對於 N=7 時,我們將有 4 種劃分的方案。

輸入格式

輸入包括一行,僅一個整數,表示 N(1N39)的值。

輸出格式

輸出包括一行,僅一個整數,曉萌可以劃分對應 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;
}