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]对调,然后从小到大排序,因为越小的数在越前面,数列越小

时间: 2024-12-10 16:50:47

poj1833---字典序算法的相关文章

生成全排列的字典序算法

字典序算法如下: 设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=min{pk|pk>pj,k>i} 3)对换pi,pk 4)再将pj+1......pk-1pkpk+1pn倒转得到排列p’’=p1p2.

寻找全排列的下一个数(字典序算法实现)

给出一个正整数,找出这个正整数所有数字全排列的下一个数.通俗的说就是在一个整数所包含数字的全部组合中,找到一个大于且仅大于原数的新整数.举例: 如果输入:12345,则返回12354 如果输入:12354,则返回12435 如果输入:12435,则返回12453 思路: 字典序算法: 从后向前查看逆序区,找到逆序区域的前一位,作为数字置换的边界: 逆序区是指:数字大小(从左到右)排序一定会是从大到小. 所以从右往左找,第一个右边值大于左边值的位置,那么右边这个位置就是逆序区的起始点. 从右向左,

什么是字典序算法?

@Test public void test() { int[] nums={1,5,3,2,4}; int[] nearestNumber = findNearestNumber(nums); System.out.println(Arrays.toString(nearestNumber));} static int[] findNearestNumber(int[] numbers) { int[] numbersCopy = Arrays.copyOf(numbers, numbers.

全排列的生成算法

[复制转载] //全排列的生成算法 // 全排列的生成算法就是对于给定的字符集,用有效的方法将所有可能的全排列无重复无遗漏地枚举出来.任何n个字符集的排列都可以与1-n的n个数字的排列一一对应, // 因此在此就以n个数字的排列为例说明排列的生成法. // n个字符的全体排列之间存在一个确定的线性顺序关系.所有的排列中除最后一个排列外,都有一个后继:除第一个排列外,都有一个前驱.每个排列的后继都可以从 // 它的前驱经过最少的变化而得到,全排列的生成算法就是从第一个排列开始逐个生成所有的排列的方

数据结构中常见经典算法

华山大师兄 排序:拓扑排序算法 字典序算法 编程珠玑:位图法排序 树:红黑树总结 B+树与B*树小结 B-树小结汇总 平衡二叉树(AVL树)小结 Trie--字典树 图的遍历:深度优先遍历与广度优先遍历 最小生成树:最小生成树-Prim算法和Kruskal算法 最短路径:最短路径—Dijkstra算法和Floyd算法

【codeup】1959: 全排列 及全排列算法详解

题目描述 给定一个由不同的小写字母组成的字符串,输出这个字符串的所有全排列.我们假设对于小写字母有'a' < 'b' < ... < 'y' < 'z',而且给定的字符串中的字母已经按照从小到大的顺序排列. 输入 输入只有一行,是一个由不同的小写字母组成的字符串,已知字符串的长度在1到6之间. 输出 输出这个字符串的所有排列方式,每行一个排列.要求字母序比较小的排列在前面.字母序如下定义:已知S = s1s2...sk , T = t1t2...tk,则S < T 等价于,存

字典序全排列

给出正整数n,则1~n这n个数可以构成n!种排列,把这些排列按照从小到大的顺序(字典顺序)列出,如n=3时,列出1 2 3,1 3 2,2 1 3,2 3 1,3 1 2,3 2 1 这6个排列. 字典序算法如下: 假设这n个数的某一个排列为 P: P1 P2 P3...Pj-1 Pj Pj+1...Pk-1 Pk Pk+1...Pn 1.从该序列的最右端开始向左找出第一个比与自己相邻的右边数小的数,记其下标为j,即j = max{i|Pi<pi+1}. 2.找出Pj右边比Pj大的最小数Pk.

全排列 字典序全排列

全排列递归的方法参考 leetcode 47 字典序算法:升序 参考https://www.jianshu.com/p/58ae30cf6bca 实现: 判断了是否相等 计算全排列的数量方法为 n!/ (m!*p!*...)   m,p为重复的数字的重复量 参考 https://blog.csdn.net/sinat_36215255/article/details/78197129 #include<iostream> #include<algorithm> #include&l

ACM POJ 1146 ID Codes

题目大意:输入一个字符串,输出它的下一个字典序排列. 字典序算法思想: 1.从右向左寻找字符串找出第一个a[i]<a[i+1]的位置i; 2.从右向左找出第一个大于a[j]的元素a[i]; 3.swap(a[i],a[j]) 4.将a[i]......到a[stelen(a)]倒序 5.输出a 代码如下: #include<iostream> #include<cstdio> #include <cstring> #include<algorithm>