1. 程式人生 > 實用技巧 >遞迴實現組合型列舉

遞迴實現組合型列舉

題目描述

從 1~n 這 n 個整數中隨機選出 m 個,輸出所有可能的選擇方案。

輸入格式

兩個整數 n,m ,在同一行用空格隔開。

輸出格式

按照從小到大的順序輸出所有方案,每行1個。

首先,同一行內的數升序排列,相鄰兩個數用一個空格隔開。

其次,對於兩個不同的行,對應下標的數一一比較,字典序較小的排在前面(例如1 3 5 7排在1 3 6 8前面)。

資料範圍

n>0
0\(\leq\) m \(\leq\) n
n+(n-m) \(\leq\) 25

輸入樣例

5 3

輸出樣例

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~n的每一個數字都有選與不選兩種情況。當選擇每一個數字時,相應的計數器都ans會加1。當ans==m時,輸出選擇的數字即可。
具體細節請見與程式碼註釋。

遞迴C++ 程式碼

#include<iostream>
using namespace std;
int n,m;
int stu[30];
void dfs(int u,int ans)
{
    if(u>n+1)//這時的選擇的數字範圍已經不在1~n之間了。為了防止程式陷入死迴圈應當及時結束函式
    return;
    if(ans>=m)//將選擇的m個數字輸出
    {
        for(int i=1;i<=n;i++)
        if(stu[i]==1)
        cout<<i<<" ";
        cout<<endl;
        return;
    }
    stu[u]=1;//選擇數字u
    dfs(u+1,ans+1);//在選擇數字u的基礎上進行深度優先遍歷,這時因為選擇了數字u,應當使ans+1.
    stu[u]=0;//回溯,消除選擇數字u帶來的影響,便於接下來對不選擇數字u進行操作
    stu[u]=2;//不選擇數字u
    dfs(u+1,ans);//不在選擇數字u的基礎上進行深度優先遍歷,這時因為沒有選擇數字u,應當時ans保持不變.
    stu[u]=0;//回溯,消除沒有選擇數字u帶來的影響,便於接下來的操作
}
int main()
{
    ios::sync_with_stdio(false);//關閉輸入流同步,提高讀寫效率
    cin.tie(0);
    cin>>n>>m;
    dfs(1,0);//從數字1開始進行深度優先遍歷
    return 0;
}

思考題

如果要求使用非遞迴方法,該怎麼做呢?