1. 程式人生 > 其它 >Acwing 93.遞迴實現組合型列舉

Acwing 93.遞迴實現組合型列舉

連結: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; 
}