排列问题Permutation

1. 问题描述:

输入大于0的自然数N,输出1~N的全排列数字。

如:N=3,输出123,132,213,231,321,312.

思路:   

全排列是将一组数按一定顺序进行排列,如果这组数有n个,那么全排列数为n!个。现以{1, 2, 3, 4, 5}为
例说明如何编写全排列的递归算法。

1、首先看最后两个数4, 5。 它们的全排列为4 5和5 4, 即以4开头的5的全排列和以5开头的4的全排列。
由于一个数的全排列就是其本身,从而得到以上结果。
2、再看后三个数3, 4, 5。它们的全排列为3 4 5、3 5 4、 4 3 5、 4 5 3、 5 3 4、 5 4 3 六组数。
即以3开头的和4,5的全排列的组合、以4开头的和3,5的全排列的组合和以5开头的和3,4的全排列的组合.
从而可以推断,设一组数p = {r1, r2, r3, ... ,rn}, 全排列为perm(p),pn = p - {rn}。
因此perm(p) = r1perm(p1), r2perm(p2), r3perm(p3), ... , rnperm(pn)。当n = 1时perm(p} = r1。
为了更容易理解,将整组数中的所有的数分别与第一个数交换,这样就总是在处理后n-1个数的全排列。

#include <iostream>

using namespace std;

int N;

void permute(int*, int*, int, int);
int arrTodigit(int*, int);
void swap(int &a, int &b);

int main()
{
	cin >> N;
	if (N < 1)
	{
		cout << "请输入大于1的整数!" << endl;
		system("pause");
		return -1;
	}

	int* arr_in = new int[N];

	int N_out=1;
	for (int i = 1; i <= N; i++)//N个自然数全排列,可得到N!个排列数
	{
		N_out *= i;
		arr_in[i - 1] = i;
	}

	int* arr_out = new int[N_out];

	permute(arr_in, arr_out, 0, N - 1);

	for (int i = 0; i < N_out; i++)
	{
		cout << arr_out[i] << endl;
	}

	delete[] arr_in;
	delete[] arr_out;

	system("pause");
	return 0;

}

void permute(int *arr_in, int *arr_out, int k, int m)
{
	static int u = 0;
	if (k > m)
	{
		arr_out[u++] = arrTodigit(arr_in, N);
	}
	else
		for (int i = k; i < N; ++i)
		{
			swap(arr_in[k], arr_in[i]);
			permute(arr_in, arr_out, k + 1, N - 1);
			swap(arr_in[k], arr_in[i]);
		}
}

int arrTodigit(int *arr,int n)
{
	int s = 0;
	for (int i = 0; i < n; ++i)
		s = s + arr[i] * pow(10, n - i - 1);

	return s;
}

void swap(int & a, int & b)
{
	int t = 0;
	t = a;
	a = b;
	b = t;
}

若要求“小数优先”原则,在把第一个元素与后面交换时有一个技巧:我们发现这个元素后面的数是已经从小到大排好序的,利用这个特点

在用于交换的函数rearr中,我们可以将那个数插在我们要交换的位置上,而那个数到交换位置之间的所有数向前挪一位,这样就保证了小数依旧优先。

void rearr(int *arr,int a,int b)
{
	int i;
	int tmp = arr[b];
	for (i = b; i > a; i--)
		arr[i] = arr[i - 1];
	arr[a] = tmp;
}
 
void derearr(int *arr, int a, int b)
{
	int i;
	int tmp = arr[a];
	for (i = a; i <b; i++)
		arr[i] = arr[i + 1];
	arr[b] = tmp;
}

 2.问题描述:

输入一列无重复大于0的整数数组A[n],和一个整数N,输出所有和等于N的数列组合,组合中元素可重复。

如:输入{1,2,3},4;

输出{1,1,1,1},{1,1,2},{1,3},{2,1,1},{2,2},{3,1}

#include <iostream>
#include <vector>

using namespace std;

int N, S;

void permute(int*, vector<int>, int);

int main()
{
	cout << "要输入几个数字?" << endl;
	cin >> N;
	cout << "数字和是多少?" << endl;
	cin >> S;
	int* A = new int[N];
	for (int i = 0; i < N; ++i)
		cin >> A[i];

	vector<int> arr_out;

	permute(A, arr_out, S);

	system("pause");

	return 0;

}

void permute(int * arr, vector<int> a1, int sum)
{
	//将sum==0作为递推终点条件,每层减去一个arr中的元素,直至sum被消耗完即找到一组符合条件的数字
	if (sum == 0)
	{
		for (int i = 0; i < a1.size(); ++i)
			cout << a1[i] ;
		cout << endl;
	}
	if (sum < 0)
		return;
	else
	{
		for (int i = 0; i < N; ++i)
		{
			a1.push_back(arr[i]);
			//sum = sum - arr[i];//sum生命周期为本循环,将会把sum的值传递给同层循环
			permute(arr, a1, sum - arr[i]);
			a1.pop_back();
		}
	}
}

猜你喜欢

转载自blog.csdn.net/Mei_ZS/article/details/83443778
今日推荐