1. 程式人生 > >HDU1028 整數劃分問題

HDU1028 整數劃分問題

Game of Connections

This is a small but ancient game. You are supposed to write down the numbers 1, 2, 3, ... , 2n - 1, 2n consecutively in clockwise order on the ground to form a circle, and then, to draw some straight line segments to connect them into number pairs. Every number must be connected to exactly one another. And, no two segments are allowed to intersect.  It's still a simple game, isn't it? But after you've written down the 2n numbers, can you tell me in how many different ways can you connect the numbers into pairs? Life is harder, right? 

Input

Each line of the input file will be a single positive number n, except the last line, which is a number -1. You may assume that 1 <= n <= 100. 

Output

For each n, print in a single line the number of ways to connect the 2n numbers into pairs. 

Sample Input

2
3
-1

Sample Output

2
5

 整數劃分問題是將一個正整數n拆成一組數連加並等於n的形式,且這組數中的最大加數不大於n。     如6的整數劃分為,共11種。

  6
    5 + 1
    4 + 2, 4 + 1 + 1
    3 + 3, 3 + 2 + 1, 3 + 1 + 1 + 1
    2 + 2 + 2, 2 + 2 + 1 + 1, 2 + 1 + 1 + 1 + 1
    1 + 1 + 1 + 1 + 1 + 1

下面介紹一種通過遞迴方法得到一個正整數的劃分數。          遞迴函式的宣告為 int split(int n, int m);其中n為要劃分的正整數,m是劃分中的最大加數(當m > n時,最大加數為n),   1 當n = 1或m = 1時,split的值為1,可根據上例看出,只有一個劃分1 或 1 + 1 + 1 + 1 + 1 + 1     可用程式表示為  if(n == 1 || m == 1) return 1;

        2 下面看一看m 和 n的關係。它們有三種關係     (1) m > n     在整數劃分中實際上最大加數不能大於n,因此在這種情況可以等價為split(n, n);     可用程式表示為  if(m > n) return split(n, n);         (2) m = n     這種情況可用遞迴表示為split(n, m - 1) + 1,從以上例子中可以看出,就是最大加     數為6和小於6的劃分之和     用程式表示為  if(m == n) return (split(n, m - 1) + 1);     (3) m < n     這是最一般的情況,在劃分的大多數時都是這種情況。     從上例可以看出,設m = 4,那split(6, 4)的值是最大加數小於4劃分數和整數2的劃分數的和。     因此,split(n, m)可表示為  split(n, m - 1) + split(n - m, m)     

#include <stdio.h>

   int split(int n, int m)
   {
      if(n < 1 || m < 1) return 0;
      if(n == 1 || m == 1) return 1;
      if(n < m) return split(n, n);
      if(n == m) return (split(n, m - 1) + 1);
      if(n > m) return (split(n, m - 1) + split((n - m), m));
  }

int main()
{
     printf("12的劃分數: %d", split(12, 12));
    return 0;
}

直接遞迴計算可能會超時,所以考慮記憶化搜尋

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e3+7;
#define mod 1000000007
ll dp[130][130];
//n為要劃分的正整數,m是劃分中最大加數
void init()
{
    memset(dp,-1,sizeof dp);
    for(int i=1;i<130;i++)
        dp[i][1]=dp[1][i]=1;
}
ll split(int n,int m)
{
    if(dp[n][m]!=-1)
        return dp[n][m];
    if(n<1||m<1)
        return dp[n][m]=0;
    if(n==1||m==1)
        return dp[n][1]=dp[1][m]=1;
    if(m>n)//m>n,最大加數為n
        return dp[n][n]=split(n,n);
    if(m==n)
        return dp[n][m]=split(n,m-1)+1;
    if(m<n)
        return dp[n][m]=split(n,m-1)+split(n-m,m);
}

int main()
{
    init();
    int n;
    while(scanf("%d",&n)!=EOF){
        printf("%lld\n",split(n,n));
    }
    return 0;
}