问题描述:
输入整数N,按照字典序从小到大打印出1-N的去所有排列。两个序列的字典序大小关系等价于从头开始第一个不相同处的大小关系,(例如(1,2,3)<(3,2,1)),N=3时,输出结果是:(1,2,3)(1,3,2)(2,1,3)(2,3,1)(3,1,2)(3,2,1).
算法思想:
设集合S是保持带排列元素的集合,数组A保持排列的元素。
如果集合S为空,则表示完成了一个排列,不再继续递归,否则将S中的元素V加入到A中,且S = S-{V},继续递归寻找下一个可以加入到排列中的元素。
#include<iostream>
using namespace std;
void print_permutation(int n, int *A, int cur)
{
int i, j;
if (cur == n)//递归边界
{
for (i = 0; i < n; i++)
cout << A[i];
cout << endl;
}
else for (i = 1; i <= n; i++)//尝试在A[cur]中添各种整数
{
int ok = 1;
for (j = 0; j < cur; j++)
if (A[j] == i)ok = 0;//如果i已经在A[0]-A[cur-1]中出现过,则不能再选
if (ok)
{
A[cur] = i;
print_permutation(n, A, cur + 1);//递归调用!
}
}
}
int main()
{
int n, A[100], cur = 0;
cout << "输入小于100的整数" << endl;
while (cin >> n)
{
for (int i = 0; i<n; i++){
A[i] = i + 1;
}
print_permutation(n, A, cur);
}
return 0;
}
7.2.3解答树!#include<iostream>
#include<algorithm>
using namespace std;
void print(int n,int*p,int *A,int cur)//p只是把地址传过来了
{
int i, j;
if (cur == n)
{
for (i = 0; i < n; i++)
{
cout << A[i];
}
cout << endl;
}
else for (i = 0; i <n; i++)
if(!i||p[i] != p[i - 1]) //只需检查P的第一个元素和所有与前面不一样的元素即可
{
int c1=0,c2=0;
for (j = 0; j < cur; j++)
if (A[j] == p[i])c1++;
for (j = 0; j < n;j++)
if (p[j] == p[i])c2++;
if (c1<c2)
{
A[cur] =p[i];
print(n, p,A, cur + 1);
}
}
}
int main()
{
int n,i, A[100],cur=0; int p[100];
while (cin >> n)
{
for ( i = 0; i < n; i++)
{
cin >> p[i];
}
sort(p, p + n);
print(n, p,A,cur);
}
return 0;
}
虽然最后一个排列没有下一个排列,用next_permutation会返回false,但是使用了这个方法后,序列会变成字典序列的第一个,如cba变成abc。prev_permutation同理。
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int n, p[100];
cin >> n;
for (int i = 0; i < n; i++)
cin >> p[i];
sort(p, p + n);
do
{
for (int i = 0; i < n; i++)
cout << p[i];
cout << endl;
} while (next_permutation(p, p + n));
return 0;
}