您的位置:首页 > 其它

foj 1571 排列的字典序问题

2010-10-25 16:04 141 查看
n个元素{1,2,...,n}有n!个不同的排列。将这n!个排列按字典序排列并编号为0,1,...,n!-1。每个排列的编号为其字典序值。例如,当n=3时,6个不同排列的字典序值如下:

字典序值012345
排列123132213231312321
给定n,以及n个元素{1,2,...,n}的一个排列,计算出这个排列的字典序值,以及按字典序排列的下一个排列。



Input

输入包括多组数据。
每组数据的第一行是元素个数n(1<=n<=13),接下来1行是n个元素{1,2,...,n}的一个排列。



Output

对于每组数据,输出两行,第一行是字典序值,第2行是字典序排列的下一个排列。



Sample Input

8 2 6 4 5 8 1 7 3



Sample Output

8227 2 6 4 5 8 3 1 7 

http://acm.fzu.edu.cn/problem.php?pid=1571

 

字典序法中,对于数字1、2、3......n的排列,不同排列的先后关系是从左到右逐个比较对应的数字的先后来决定的。例如对于5个数字的排列 12354和12345,排列12345在前,排列12354在后。按照这样的规定,5个数字的所有的排列中最前面的是12345,最后面的是 54321。
字典序算法如下:
设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)对换pi,pk
4)再将pj+1......pk-1pkpk+1pn倒转得到排列p'=p1p2.....pj-1pjpn.....pk+1pkpk-1.....pj+1,这就是排列p的下一个下一个排列。

 

 

 
#includee<iostream>
#include<cmath>
using namespace std;
int main()
{
int n,i,j,Min,k,t;
int a[13];
__int64 sum;
int b[14];
int c[13];

freopen("in.txt","r",stdin);

sum=1;
for(i=1;i<=13;i++)
{
sum*=i;
b[i]=sum;
}
while(scanf("%d",&n)!=EOF)
{
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
c[i]=a[i]-1;
}
for(i=1;i<n;i++)
for(j=0;j<=i;j++)
{
if(a[j]<a[i])c[i]--;
}
sum=0;b[0]=1;
for(i=0;i<n-1;i++)
{
sum+=c[i]*b[n-i-1];
//printf("%d ",c[i]);
}
//printf("/n");
t=-1;
for(i=n-1;i>=1;i--)
if(a[i-1]<a[i])
{
t=i-1;
break;
}
Min=14;
for(j=t+1;j<n;j++)
if(Min>a[j]&&a[j]>a[t])
{
Min=a[j];
k=j;
}
if(t!=-1)
swap(a[t],a[k]);
i=t+1;
j=n-1;
while(i<j)
{
swap(a[i++],a[j--]);
}
printf("%I64d/n",sum);
for(i=0;i<n;i++)
printf(i!=n-1?"%d ":"%d/n",a[i]);
}
return 0;
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: