poj1833---字典序算法

题意:给定一个序列,求它的下k个排列

#include <stdio.h>

#include <stdlib.h>



int cmp(const void *a,const void *b)

{

    return (*(int *)a-*(int *)b);

}



void getNext(int *arr,int n)

{

    int i,j,flag,t;

    for(i=n-2;i>=0;i--)

    {

        if(arr[i]<arr[i+1])

            break;

    }//找到左边小于右边,并返回左边数的下标

    if(i==-1)

    {

        qsort(arr,n,sizeof(arr[0]),cmp);

        return ;

    }//以防遇到递减数列,找不到

    flag=i+1;

    for(j=i+2;j<n;j++)//当i==n-2,不走这个循环,那么倒数第二个数后面就只有一个数比他大,可能就要直接交换保证最小增长

    {

        if(arr[j]>arr[i])//假设说倒数第二个数大于倒数第三个数,可是倒数第一个数比倒数第三个数小

            flag=j;//flag始终记录当前比a[i]大的值的下标

    }

    t=arr[flag];

    arr[flag]=arr[i];

    arr[i]=t;

    qsort(&arr[i+1],n-1-i,sizeof(arr[0]),cmp);//有可能要qsort一个数

}



int main()

{

    int a[1025],ncase,i;

    scanf("%d",&ncase);

    while(ncase--)

    {

        int n,k;

        scanf("%d%d",&n,&k);

        for(i=0;i<n;i++)

        {

            scanf("%d",&a[i]);

        }

        for(i=0;i<k;i++){

        getNext(a,n);

        }

        for(i=0;i<n;i++)

        {

            printf("%d ",a[i]);

        }

        printf("\n");

    }

    return 0;

}
for(j=i+2;j<n;j++)//当i==n-2,不走这个循环,那么倒数第二个数后面就只有一个数比他大,可能就要直接交换保证最小增长

    {

        if(arr[j]>arr[i])//假设说倒数第二个数大于倒数第三个数,可是倒数第一个数比倒数第三个数小

            flag=j;//flag始终记录当前比a[i]大的值的下标

    }

这段代码有3涉及到最后两个,三个,四个的情况

字典序算法描述:从右边开始,遍历整个数列,先取数列的倒数第二个数与倒数第一个数相比,如果左边大于右边则让i--,让倒数第三个与倒数第二个相比,如果倒数第三个小于倒数第二个

那么此时循环结束,记下倒数第三个数的下标

否则直到找到左边一个数大于右边一个数为止,不过可能这个数列一开始就一个递减数列,i==0也不行,i==-1,循环被遍历完

此时在getNext里面直接qsort这个数列

分为四种情况:

1.倒数第2个<倒数第1个

2.倒数第3个<倒数第2个    a. 倒数第3个>倒数第1个 b. 倒数第3<倒数第1个

3.倒数第四个....反正从倒数第2个开始就有可能小于倒数第四个

flag的作用啊!!

字典序算法核心:为保证最小增长,将a[i]后面大于a[i]的最小的数与a[i]对调,然后从小到大排序,因为越小的数在越前面,数列越小

 

你可能感兴趣的:(poj)