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();
}
}
}