ACM:回溯法,枚举排列

(一)生成1~n的排列

分析:用递归的思想解决:先输出所有以1开头的排列(这一步是递归调用),然后输出以2开头的排列(又是递归调用),接着是以3开头的排列……最后才是以n开头的排列。

伪代码:

void print_permutation(序列A, 集合S) {

if(S为空) 输出序列A;

else 按照从小到大的顺序依次考虑S的每个元素v {

print_permutation(在A的末尾填加v后得到的新序列,S-{v});

下面是实现代码:

#include <iostream>
using namespace std;

const int MAXN = 1000;
int A[MAXN], n;

void print_permutation(int n, int *A, int cur) {
	if(cur == n) {    //递归边界
		for(int i = 0; i < n; ++i) cout << A[i] << " ";
		cout << endl;
	}else {
		for(int i = 1; i <= n; ++i) {    //尝试在A[cur]中填各种整数i
			int ok = 1;
			for(int j = 0; j < cur; ++j) {
				if(A[j] == i) ok = 0;   //如果i已经在A[0]~A[cur-1]出现过,则不能再选
			}
			if(ok) {   //i在A[0]~A[cur-1]<span style="font-family: Arial, Helvetica, sans-serif;">中没有出现过,所以可以把i放进A[cur]</span>

				A[cur] = i;
				print_permutation(n, A, cur+1);  //递归调用
			}
		}
	}
}

int main() {
	cin >> n;
	print_permutation(n, A, 0);
	return 0;
}

(二)生成可重集的排列

输入数组P,按照字典序输出数组P各元素的所有全排列。

#include <iostream>
#include <algorithm>
using namespace std;

const int MAXN = 1000;
int A[MAXN], P[MAXN], n;

void print_permutation(int n, int *P, int *A, int cur) {
	if(cur == n) {
		for(int i = 0; i < n; ++i) cout << A[i] << " ";
		cout << endl;
	}else for(int i = 0; i < n; ++i) if(!i || P[i] != P[i-1]){  //if条件句确保了不会重复递归调用相同的元素,保证了我们枚举的下标i应不重复不遗漏地取遍所有P[i]值
		int c1 = 0, c2 = 0; 
		for(int j = 0; j < cur; ++j) if(P[i] == A[j]) c1++;  //A[0]~A[cur-1]中P[i]出现的次数放在c1中
		for(int j = 0; j < n; ++j) if(P[i] == P[j]) c2++;  //P数组中P[i]的出现次数放在c2中。
		if(c1 < c2) {    //只要c1<c2就能递归调用,这样就保证了不会遗漏相同的元素。
			A[cur] = P[i];
			print_permutation(n, P, A, cur+1);
		}
	}
}

int main() {
	cin >> n;
	for(int i = 0; i < n; ++i) cin >> P[i];
	sort(P, P+n);
	print_permutation(n, P, A, 0);
	return 0;
}

(三)生成下一个排列:

枚举所有排列的另一个方法是从字典序最小排列开始,不停的调用“求下一个排列”的过程。

利用STL里面的next_permutation来求下一个排列,

#include <iostream>
#include <cstdio>
#include <algorithm>

#define MAXN 1000

using namespace std;

int P[MAXN];

int main(){
	int n;
	cin >> n;
	for(int i = 0; i < n; ++i){
		cin >> P[i];
	}
	sort(P, P+n);   // 排序,得到p的最小排列
	do{
		for(int i = 0; i < n; ++i){
			cout << P[i] << " ";
		}
		cout << endl;
	}while(next_permutation(P, P+n));
	return 0;
}

    原文作者:回溯法
    原文地址: https://blog.csdn.net/u010470972/article/details/36485123
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞