Acwing 93.遞迴實現組合型列舉
阿新 • • 發佈:2021-11-17
連結:https://www.acwing.com/problem/content/description/95/
題目:
從 1∼n 這 n 個整數中隨機選出 m 個,輸出所有可能的選擇方案。
輸入格式
兩個整數 n,m ,在同一行用空格隔開。
輸出格式
按照從小到大的順序輸出所有方案,每行 1 個。
首先,同一行內的數升序排列,相鄰兩個數用一個空格隔開。
其次,對於兩個不同的行,對應下標的數一一比較,字典序較小的排在前面(例如 1 3 5 7 排在 1 3 6 8 前面)。
資料範圍
n>0 ,
0≤m≤n ,
n+(n−m)≤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
思路:
同樣是採用dfs的方式從第一位到最後一位列舉。但因為是組合型,沒有順序差別,所以需要篩選。
如果規定從前往後列舉時每一個數都必須比前面一個數大,最後是遞增的關係,那麼組合型列舉就可以實現。
比如:1,3,5這三個數,在列舉時可能有135,153,315,351,513,531這六種情況,如果按照遞增順序列舉,那麼只有一種情況會保留下來,也就是135,這樣就可以避免重複列舉。
在列舉時傳入引數start(從哪個數開始列舉),可以實現從小到大列舉。
剪枝思路:如果一種情況一定無解,就不需要再運算,直接剪去。
當還需要列舉的數的數量大於還剩下可以列舉的數的數量時,一定無解。
m-u+1>n-start+1,即m-u-n+start>0;
可以看到執行時間快了將近三倍
題解:
#include<bits/stdc++.h> using namespace std; const int N=30; int n,m; int ans[N]; void dfs(int u,int start) { if(m-u-n+start>0) return; //剪枝,剪去一定無解的分支 if(u>m) //m個數已選擇完畢 { for(int i=1;i<=m;i++) cout<<ans[i]<<' '; cout<<endl; return; } for(int i=start;i<=n;i++) { ans[u]=i; dfs(u+1,i+1); ans[u]=0; //恢復現場 } return; } int main() { cin>>n>>m; dfs(1,1); return 0; }