首先了解一下,什么是字典序
字典序如下:
设P是1~n的一个
全排列:p=p1p2......pn=p1p2......pj-1pjpj+1......pk-1pkpk+1......pn
1)从排列的右端开始,找出第一个比右边数字小的数字的序号j(j从左端开始计算),即 j=max{i|pi<pi+1}
2)在pj的右边的数字中,找出所有比pj大的数中最小的数字pk,即 k=max{i|pi>pj}(右边的数从右至左是递增的,因此k是所有大于pj的数字中序号最大者)
3)对换pj,pk
4)再将pj+1......pk-1pkpk+1......pn倒转得到排列p'=p1p2.....pj-1pjpn.....pk+1pkpk-1.....pj+1,这就是排列p的下一个排列。
举个例子
123这个序列,下一个序列依次为132,312,321,231,132
例如:设有排列(p)=2763541,按照字典式排序,它的下一个排列是什么?
- 2763541 (找最后一个正序35);
- 2763541 (找3后面比3大的最后一个数4);
- 2764531 (交换3,4的位置);
- 2764135 (把4后面的5,3,1反转)。
void swap(int *arr, int i, int j)
{
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
void reverse(int *arr, int first, int last)
{
while( first != last && first != --last)
{
swap(arr, first, last);
first++;
}
}
//true 数组元素顺序改变
//false 数组元素顺序没有改变
bool permutation(int *arr, int N)
{
if(N == 0 || N == 1)
return false;
int last = N;
//ii代表i-1
int ii = last - 1;
int i = ii - 1;
while(true)
{
if(arr[i] < arr[ii])
{
int j = last - 1;
while( !(arr[i] < arr[j]) )
j--;
swap(arr, i, j);
//i位置后(不包含i)元素逆序
reverse(arr, ii, last);
return true;
}
//已是递减排序,无下一个排序了。
if(i == 0)
{
//全部倒序,恢复最初状态
reverse(arr, i, last);
return false;
}
i--; ii--;
}
}
int main()
{
int arr[] = {1,2,3};
int size = sizeof(arr) / sizeof(int);
for(int i = 0; i < size; i++)
cout << arr[i] << " ";
cout << endl;
while(permutation(arr, size))
{
for(int i = 0; i < size; i++)
cout << arr[i] << " ";
cout << endl;
}
system("pause");
return 0;
}
Ignatius and the Princess II Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 7738 Accepted Submission(s): 4579
Problem Description
Now our hero finds the door to the BEelzebub feng5166. He opens the door and finds feng5166 is about to kill our pretty Princess. But now the BEelzebub has to beat our hero first. feng5166 says, "I have three question for you, if you can work them out, I will release the Princess, or you will be my dinner, too." Ignatius says confidently, "OK, at last, I will save the Princess."
"Now I will show you the first problem." feng5166 says, "Given a sequence of number 1 to N, we define that 1,2,3...N-1,N is the smallest sequence among all the sequence which can be composed with number 1 to N(each number can be and should be use only once in this problem). So it's easy to see the second smallest sequence is 1,2,3...N,N-1. Now I will give you two numbers, N and M. You should tell me the Mth smallest sequence which is composed with number 1 to N. It's easy, isn't is? Hahahahaha......"
Can you help Ignatius to solve this problem?
"Now I will show you the first problem." feng5166 says, "Given a sequence of number 1 to N, we define that 1,2,3...N-1,N is the smallest sequence among all the sequence which can be composed with number 1 to N(each number can be and should be use only once in this problem). So it's easy to see the second smallest sequence is 1,2,3...N,N-1. Now I will give you two numbers, N and M. You should tell me the Mth smallest sequence which is composed with number 1 to N. It's easy, isn't is? Hahahahaha......"
Can you help Ignatius to solve this problem?
Input
The input contains several test cases. Each test case consists of two numbers, N and M(1<=N<=1000, 1<=M<=10000). You may assume that there is always a sequence satisfied the BEelzebub's demand. The input is terminated by the end of file.
Output
For each test case, you only have to output the sequence satisfied the BEelzebub's demand. When output a sequence, you should print a space between two numbers, but do not output any spaces after the last number.
Sample Input
6 4 11 8
Sample Output
1 2 3 5 6 4 1 2 3 4 5 6 7 9 8 11 10
Author
Ignatius.L
输入n m,求第m个全排列,这题要用到c++的
next_permutation函数
next_permutation函数的原理如下:
在当前序列中,从尾端向前寻找两个相邻元素,前一个记为*i,后一个记为*t,并且满足*i < *t。然后再从尾端
寻找另一个元素*j,如果满足*i < *j,即将第i个元素与第j个元素对调,并将第t个元素之后(包括t)的所有元
素颠倒排序,即求出下一个序列了。
在当前序列中,从尾端向前寻找两个相邻元素,前一个记为*i,后一个记为*t,并且满足*i < *t。然后再从尾端
寻找另一个元素*j,如果满足*i < *j,即将第i个元素与第j个元素对调,并将第t个元素之后(包括t)的所有元
素颠倒排序,即求出下一个序列了。
next_permutation()函数功能是输出所有比当前排列大的排列,顺序是从小到大。
而prev_permutation()函数功能是输出所有比当前排列小的排列,顺序是从大到小。
而prev_permutation()函数功能是输出所有比当前排列小的排列,顺序是从大到小。
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int n,m;
int a[1000+5];
while(cin>>n>>m)
{
for(int i=0;i<n;i++)
a[i]=i+1;
for(int i=0;i<m-1;i++)
next_permutation(a,a+n);
for(int i=0;i<n;i++)
{
if(i!=n-1)cout<<a[i]<<' ';
else cout<<a[i]<<endl;;
}
}
return 0;
}