遞歸實現排列組合

一、組合問題(只選不排)

在這裏插入圖片描述
在這裏插入圖片描述

本題要求實現對n以內的整數進行排列組合(只選不排)。
實現思路就是對於當前第u位數(u <= n),分爲選與不選兩種情況,構成了一棵二叉選擇樹,最終的葉節點就是答案。
爲了節省空間和簡化操作,使用狀態壓縮,對於state,第i位爲1表示i這個數被選中。
#include<iostream>
using namespace std;
int n;
void dfs(int u, int state) {//u表示判斷進度,表示對第u個數(從0開始)進行選擇
	if (u == n) {
		for (int i = 0; i < n; i++) {
			if (state >> i & 1) {
				cout << i + 1 << " ";
			}
		}
		cout << endl;
		return;
	}

	dfs(u + 1, state);// 分支:不用這個數
	dfs(u + 1, state | 1 << u);//用這個數

}

int main() {
	cin >> n;
	dfs(0, 0);
	return 0;
}
下面看一道例題:

在這裏插入圖片描述
在這裏插入圖片描述

這一題與上一題的區別是,限制了選擇的個數:上一題要求在n個數裏面任選,這一題要求只選m個數。所以只需要在原先的代碼的基礎上加上個數判斷即可。
#include <iostream>

using namespace std;

int n,m;
void dfs(int u , int sum, int state){//u表示對第u個數(從0開始)進行選擇,sum表示已選的個數
    if (sum + n - u < m) return;
    if (sum == m){//此時的邊界不再是n == u,只要滿足了選擇個數就要退出
        for (int i = 0; i < n; i++){
            if(state >> i & 1){
                cout << i + 1 << " ";
            }
        }
        cout << endl;
        return;
    }
    
    dfs(u + 1, sum + 1, state | 1 << u );
    dfs(u + 1, sum, state);
}

int main(){
    
    cin >> n >> m;
    dfs(0,0,0);
    
    return 0;
}
二、排列問題

在這裏插入圖片描述

排列問題是選了再排,所以既要保證元素唯一性又要保證順序唯一性。state狀態壓縮只能保證元素的唯一性,而無法保證順序性。所以需要額外開闢數組記錄每一次的選擇狀態。

主要思想如下:首先將選取的位置看做n個坑,對於第u個坑(u從0開始)需要考慮選哪個數來填坑(而不再是考慮填與不填這種哲學問題了)。所以能填坑的就是那些還未被選擇的那些數,每選一個數就是一種可能,要用數組記錄下來。如此循環,等第n個坑也被填完的時候就是一種結果。

#include <iostream>
#include <vector>
using namespace std;
int n;
vector<int> path;
void dfs(int u, int state){//對第u個坑,放哪些數, 用state保證每個數只被選一次
    
    if (u == n){
       for(auto x : path) cout << x << " ";
       cout << endl;
       return;
    }
    
    for(int i = 0; i < n; i ++){
        if ( !(state >> i & 1) ){
            path.push_back(i + 1);//在第u個坑上填i + 1
            dfs(u + 1, state | 1 << i);
            path.pop_back();//擦屁股
        }
    }
}

int main(){
    cin >> n;
    dfs(0,0);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章