1. 程式人生 > >OpenJudge簡單的整數劃分問題兩種方法(DFS)(動態規劃0ms),全域性題號7215,已AC

OpenJudge簡單的整數劃分問題兩種方法(DFS)(動態規劃0ms),全域性題號7215,已AC

2:簡單的整數劃分問題

總時間限制: 
100ms 
記憶體限制: 
65536kB
描述

將正整數n 表示成一系列正整數之和,n=n1+n2+…+nk, 其中n1>=n2>=…>=nk>=1 ,k>=1 。
正整數n 的這種表示稱為正整數n 的劃分。正整數n 的不同的劃分個數稱為正整數n 的劃分數。

輸入
標準的輸入包含若干組測試資料。每組測試資料是一個整數N(0 < N <= 50)。
輸出
對於每組測試資料,輸出N的劃分數。
樣例輸入
5
樣例輸出
7
提示
5, 4+1, 3+2, 3+1+1, 2+2+1, 2+1+1+1, 1+1+1+1+1
方法一:採用DFS的方法,對目標進行深度搜索,如圖所示
上面只畫了一部分的結點,就類似於一個結點一個結點的往下搜尋,搜尋到符合結果的就cnt++.
一般能畫出這種樹狀圖的都能用DFS。DFS的核心程式碼在我的ZOJ1002文章裡有提到。
方法二:
例如數字5(以j表示),有1 2 3 4 5五個因子(下面以i代表第五個) ,每一個因子在選擇時都有選與不選兩種選擇。
例如如果選5
問題就變成 0 ,1 2 3 4 5。這就直接return了
如果不選5
問題就變成5, 1 2 3 4。
以此類推,後面的步驟和前面都是一樣的。所以我們可以把問題分解為兩種情況
(j,i) + (j-i,i) //j 代表還有多少能減 , i代表還有前i個數
方法一:
#include <iostream>
using namespace std;
int cnt=0;//記錄方案次數
int n;//輸入的數值
void dfs(int sum,int k)//sum為每次嘗試的和,k為下一結點的值
{
    
    if(sum>=n)//如果大於n就需判斷是否符合
    {
        if(sum==n)
            cnt++;
    }
    if(k<1)return;//1後面就沒了
    for(int i=k;i>0;i--)//每個結點都有1~k個分支
    {
        if(sum<n)//小於n才有新的分支
        {
            sum=sum+i;
            if(sum>=n)//例如3+2=5的情況
            {
                dfs(sum,i-1);//進入下一個結點
            }
            else
                dfs(sum,i);//例如1+1+1+1+1=5的情況,進入下一個結點
            sum=sum-i;//復原,因為一個結點會有多個分支。
        }
    }
}
int main()
{
    
    while(cin>>n)
    {
        dfs(0,n);
        cout<<cnt<<endl;
        cnt=0;
    }
    return 0;
}

方法二:
#include <iostream>
#include <cstring>
using namespace std;
int way(int i,int j);
int ways[55][55];
int main()
{
    int n;
    while(cin>>n)
    {
        memset(ways,0xff,sizeof(ways));//全部賦值為-1
        cout<<way(n,n)<<endl;
    }
    return 0;
}
int way(int i,int j)
{
    int result=0;
    if(j==0)
        return 1;
    if(i==0)
        return 0;
    if(ways[i][j]!=-1)//如果這種情況已經做過直接返回
        return ways[i][j];
    if(j>=i)
        result+=way(i,j-i);
    result+=way(i-1,j);
    ways[i][j]=result;//狀態記錄
    return result;
}