编程语言
首页 > 编程语言> > 算法:排列的字典序问题

算法:排列的字典序问题

作者:互联网

排列的字典序问题
Time Limit: 1000 ms Memory Limit: 65536 KiB
Submit Statistic
Problem Description
n个元素{1,2,……, n }有n!个不同的排列。将这n!个排列按字典序排列,并编号为0,1,…,n!-1。每个排列的编号为其字典序值。例如,当n=3时,6 个不同排列的字典序值如下:

给定n以及n个元素{1,2,……, n }的一个排列,计算出这个排列的字典序值,以及按字典序排列的下一个排列。
Input
输入数据的第1行是元素个数n(n≤20)。接下来的1行是n个元素{1,2,……, n }的一个排列。
Output
输出数据的第1行是字典序值,第2行是按字典序排列的下一个排列。
Sample Input
8
2 6 4 5 8 1 7 3
Sample Output
8227
2 6 4 5 8 3 1 7

 我们可以从从开始算,因为不能有重复,以1开头的后面有7位数有1*7!,然后以2开头的后面有六位数,但第二位要小于6,即有1、3、4、5满足,有4*6!,然后以26...开头的后面有5位数,要求第三位要小于4,即有1,3满足,有2*5!,,,依次类推。。。
       

看例子:

tot=0;

比2小的数有1个,则 tot+=1*7!;

比6小的数有4个,则 tot+=4*6!;

比4小的数有2个,则 tot+=2*5!;

比5小的数有2个,则 tot+=2*4!;

比8小的数有3个,则 tot+=3*3!;

比1小的数有0个,则 tot+=0*2!;

比7小的数有1个,则 tot+=1*1!;

比3小的数没有;

(注:在排列中,求比某个数小的数的个数时,排除之前出现过的数)
如何得到2 6 4 5 8 1 7 3的下一个排列?
    1 从尾部往前找第一个P(i-1) < P(i)的位置
            2 6 4 4 5 8 1 <-- 7 <-- 3
        最终找到1是第一个变小的数字,记录下1的位置i-1
    2 从尾部往前找到第一个大于1的数
            2 6 4 4 5 8 1 7 3 <--
        最终找到3的位置,记录位置为m
    3 交换位置i-1和m的值
            2 6 4 4 5 8 3 7 1
    4 倒序i位置后的所有数据
            2 6 4 4 5 8 3 1 7
可以用   next_permutation(data,data+n);
#include <bits/stdc++.h>
using namespace std;
//求阶乘
int fib(int n)
{
	if(n<=1)
		return 1;
	else
	{
		return fib(n-1)*n;
	}
}

//字典序,从0开始
int order(int data[],int n)
{
	int ret = 0;

	for(int i=0; i<n; i++)
	{
		int m = data[i];
		int cnt = 0;

		for(int j=i; j<n; j++)
		{
			if(m>data[j])
				cnt++;
		}

		ret+=cnt*fib(n-i-1);
	}

	return ret;
}

void swap(int data[], int i, int j)
{
	int t = data[i];
	data[i] = data[j];
	data[j] = t;
}

void reverse(int a[],int min,int n)
{//数组逆置 
    int i,j,temp;
    for(i=min,j=n-1;i<j;i++,j--)
    {
        temp=a[i];
        a[i]=a[j];
        a[j]=temp;
    }
}

void next_perm(int data[],int n)
{//求出下一个字典序 
    int min,max;
    for(int i=n-1;i>=0;i--)
    {//找出升序截止点的数组下标 
        if(data[i-1]<data[i])
        {
            min=i-1;
            break;
        }
    }
    for(int i=n-1;i>=0;i--)
    {//找出刚刚比a[min]大的数 
        if(data[i]>data[min])
        {
            max=i;
            break;
        }
    }  
    swap(data[min],data[max]);
    reverse(data,min+1,n);//注意交换的是a[min+1]到a[n] 
}

int main()
{
	int n;

	cin>>n;

	int data[1000];

	for(int i=0; i<n; i++)
		cin>>data[i];

	cout<<order(data,n)<<endl;

	next_perm(data,n);
//	next_permutation(data, data + n);

	for(int i=0; i<n; i++)
	{
		cout<<data[i]<<" ";
	}

	cout<<endl;

	return 0;
}

运行效果:
在这里插入图片描述

标签:排列,int,tot,算法,数有,data,字典
来源: https://blog.csdn.net/wl1780852311/article/details/100834712