zoukankan      html  css  js  c++  java
  • pku acm 1833 排列

    这道题目,最直观的想法是求出1到n的所有排列,然后将全部排列排序.

    但是,n最大可以是1024,1024!个排 列,几乎永远也算不出来,算出来也没有地方存放。那么,有没有公式或规律,能够很快由一个排列推算出下k个排列呢?

    实际上寻找规律或公式都是徒劳的,只能老老实实由给定排列算出下一个排列,再算出下一个排列……一直算到第k的排列。

    鉴于k的值很小,最多只有64,因此这种算法应该是可行的。

    如何由给定排列求下一个排列?

    不妨自己动手做一下。比如:“2 1 4 7 6 3 5”的下一个排列是什么?

    容易,显然是“2 1 4 7 6 5 3”,那么,再下一个排列是什么?有点难了,是“2 1 5 3 4 6 7”。

    以从“2 1 4 7 6 5 3”求出下一个排列“2 1 5 3 4 6 7”作为例子,可以总结出求给定排列的下一个排列的步骤:

    假设给定排列中的n个数从左到右是a1, a2, a3……an。

    1)从an开始,往左边找,直到找到某个aj,满足aj-1<aj

    (对上例j, 这个aj就是7, aj-1 就是4)。

    2)在aj、aj+1…… an中找到最小的比aj-1大的数,将这个数和aj-1互换位置

    (对上例, 这个数就是5,和4换完位置后的排列是“2 1 5 7 6 4 3”)。

    3)将从位置j到位置n的所有数(共n-j+1个)从小到大重新排序,排好序后,新的排列就是所要求的排列。

    (对上例,就是将“7 6 4 3”排序,排好后的新排列就是“2 1 5 3 4 6 7”)。

    当然,按照题目要求,如果a1, a2, a3……an已经是降序,那么它的下一个排序就是an, an-1, an-2……a1。

    注:上面的是基本思路,但是我们可以根据当前排列的性质,加以优化;

    对于第一步,没法优化,只好从后到前找,找到了J。

    第二布就可以优化了。循环找是可以,但是从J到J+1是倒序的,这样的话,根据有序的这个特性可以用二分查找,效率由O(n)提到到了O(log(n)).

    第三部,排序仍是不需要的,因为从J到J+1是倒序的,只需反转就OK 了,降到了O(n).

    接下来粘上代码以供参考

     1 #include<stdio.h>
     2 const int N=1015;
     3 int str[N];
     4 int n,k;
     5 
     6 void restr(int begin)
     7 {
     8     int end=n-1;
     9     int p;
    10     while(end>begin)
    11     {
    12         p=str[end];
    13         str[end]=str[begin];
    14         str[begin]=p;
    15         end--;
    16         begin++;
    17     }
    18 
    19 }
    20 
    21 int find(int p,int begin,int end)
    22 {
    23     if(begin==end)return begin;
    24     if(begin+1==end)
    25     {
    26         if(str[end]>str[p])return end;
    27         return begin;
    28     }
    29     
    30     int mid=(begin+end)/2;
    31     if(str[mid]<=str[p])return find(p,begin,mid-1);
    32     return find(p,mid,end);
    33 }
    34 
    35 
    36 void serch(int p)
    37 {
    38     int p0=find(p-1,p,n-1);//find the first number that is bigger than the value of str[p-1]
    39     int p1=str[p-1];
    40     str[p-1]=str[p0];
    41     str[p0]=p1;
    42 }
    43 
    44 void next()
    45 {
    46     int i=n-1;    
    47     while(i && str[i-1]>=str[i])i--;
    48     if(i==0){restr(0);return ;}
    49     serch(i);
    50     restr(i);            
    51 }
    52 
    53 void print()
    54 {
    55     printf("%d",str[0]);
    56     for(int i=1;i<n;i++)
    57     {
    58         printf(" %d",str[i]);
    59     }
    60     printf("\n");
    61 }
    62 
    63 int main()
    64 {
    65 
    66     scanf("%d",&n);
    67     while(scanf("%d%d",&n,&k)!=EOF)
    68     {
    69         for(int i=0;i<n;i++)scanf("%d",&str[i]);    
    70         if(n!=1)
    71         {
    72             while(k--)
    73             {
    74                 next();    
    75             }        
    76         }
    77 
    78         
    79         print();
    80     }
    81 return 0;    
    82 }

     

     

     

  • 相关阅读:
    深蓝说区块学习笔记
    Golang语言练习
    WebAssembly学习
    JMeter如何维持登录Session状态
    MySQL脏读、不可重复读、幻读及MVCC
    webrtc源码分析(7)-fec
    webrtc源码分析(9)-拥塞控制(下)-码率分配
    webrtc源码分析(8)-拥塞控制(上)-码率预估
    剑指offer刷题合集
    Visual Studio ------- 将在解决方案中单击文件名,预览文件内容功能开启与关闭
  • 原文地址:https://www.cnblogs.com/tiankonguse/p/2442575.html
Copyright © 2011-2022 走看看