动态

详情 返回 返回

簡單遞歸 - 动态 详情

Let's be better ourselves together.

種一棵樹最好的時間是十年前,其次是現在。


如何用簡單遞歸實現指數型枚舉,組合型枚舉以及排列行枚舉?

思路:我們可以把這一類題目想象成,有n個排列在一起的一列格子,我們需要按一定順序來填這些格子。

以下為三道HZOJ的題目作為例子。

235. 遞歸實現指數型枚舉

題目描述

從 1−nn 個整數中隨機選取任意多個,每種方案裏的數從小到大排列,按字典序輸出所有可能的選擇方案。

輸入

輸入一個整數 n。(1≤n≤10)

輸出

每行一組方案,每組方案中兩個數之間用空格分隔。

注意每行最後一個數後沒有空格。

樣例輸入
3
樣例輸出
1
1 2
1 2 3
1 3
2
2 3
3
樣例輸入2
4
樣例輸出2
1
1 2
1 2 3
1 2 3 4
1 2 4
1 3
1 3 4
1 4
2
2 3
2 3 4
2 4
3
3 4
4
數據規模與約定

時間限制:1 s

內存限制:256 M

100% 的數據保證 1≤n≤10

思路: 從下標為0的格子開始,依次填數,在第i個位置可以選擇的最小數字是x的情況下,實現所有指數型枚舉。當i > 0,也就是已經選擇了至少一個數,輸出一種結果。

#include <iostream>
using namespace std;

int n;
int a[20];

//在第i個位置,最小為x
void f(int x, int i) {
    if(i > 0) { //如果已經選擇了至少一個數字
        for(int j = 0;j < i;j ++) {
            if(j > 0) cout<<" ";
            cout<<a[j];
        } 
        cout<<endl;
    }
    
    for(int k = x;k <= n;k ++)
    {
        a[i] = k;
        f(k + 1, i +1);
    }
    
    return ;
}

int main()
{
    cin>>n;
    
    f(1, 0);
    return 0;
}

236. 遞歸實現組合型枚舉

題目描述

從 1−nn 個整數中隨機選取 m 個,每種方案裏的數從小到大排列,按字典序輸出所有可能的選擇方案。

輸入

輸入兩個整數 n,m。(1≤mn≤10)

輸出

每行一組方案,每組方案中兩個數之間用空格分隔。

注意每行最後一個數後沒有空格。

樣例輸入
3 2
樣例輸出
1 2
1 3
2 3
樣例輸入2
5 3
樣例輸出2
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
數據規模與約定

時間限制:1 s

內存限制:256 M

100% 的數據保證 1≤mn≤10

思路:這道題和上一道題十分類似。從下標為0的格子開始,依次填數,在第i個位置可以選擇的最小數字是x的情況下,實現所有組合枚舉。不同的是邊界條件,上一道題當i > 0時即可輸出一種結果,這道題要填滿m個格子再輸出一種結果,所以邊界條件為i >= m。

#include <iostream>
using namespace std;

int n, m;
int a[20];

void f(int x, int i) {
    if(i >= m) {
        for(int j = 0;j < m;j ++){
            if(j) cout<<' ';    
            cout<<a[j];
        }
        cout<<endl;
        return ;
    }
    
    for(int k = x;k <= n;k ++) {
        a[i] = k;
        f(k + 1, i + 1);
    }
}

int main()
{
    cin>>n>>m;
    
    f(1, 0);
    return 0;
}

237. 遞歸實現排列型枚舉

題目描述

從 1−nn 個整數排成一排並打亂次序,按字典序輸出所有可能的選擇方案。

輸入

輸入一個整數 n。(1≤n≤8)

輸出

每行一組方案,每組方案中兩個數之間用空格分隔。

注意每行最後一個數後沒有空格。

樣例輸入
3
樣例輸出
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
數據規模與約定

時間限制:1 s

內存限制:256 M

100% 的數據保證 1≤n≤8

思路:這道題其實就是輸出n的全排列。這道題需要注意的是,如何判斷當前的枚舉的這個數字是否出現過。所以我們需要使用一個bool數組來記錄它是否出現過。填數字的時候,先判斷是否出現,如果沒有出現(!st[k]),則填入數字。邊界條件是,當n個格子都填滿了, i == n,即完成了一種可能的排列。

#include <iostream>
using namespace std;

int n;
int a[10];
bool st[10];

void f(int i){
    if(i == n) {
        for(int j = 0;j < n;j ++) {
            if(j > 0) cout<<' ';
            cout<<a[j];
        }
        cout<<endl;
        return ;
    }
    
    for(int k = 1;k <= n;k ++) {
        if(!st[k]) {
            a[i] = k;
            st[k] = true;
            f(i + 1);
            st[k] = false;
        }    
    }
}

int main()
{
    cin>>n;
    f(0);
    return 0;
}

Add a new 评论

Some HTML is okay.