• 全排列


    全排列

    //这篇题解是我第一篇题解,很久以前写的,就作为我blog的第一篇文章吧

    思路

    递归。

    N个数的全排列数,观察3个数的全排列数:

    1 2 3

    1 3 2

    2 1 3

    2 3 1

    3 1 2

    3 2 1

    可以看到第一个分别是1 2 3,而各自后面所跟着的,恰恰是剩下的数的全排列,以1为例,后面的 2 3 和 3 2是2、3的全排列

    又比如4个数全排列:

    全排列示意

    即先依字典序安排一个数在首位,而剩下的数则在后面进行全排列,这就体现出了递归的思想,由此可见我们可以用递归来处理这个问题

    抽象出来就是

    Permutation(N){
    	Head(); 
    	Permutation(N-1); 
    }
    

    代码与说明

    
    /*
    之前的代码是
    void permutation(char *s) {
        if (strlen(s) == 1) {
            printf("%c
    ", s[0]);
        }
        else {
            int i;
            for (i = 0; i < strlen(s); i++) {
                printf("%c",s[i]);
                char s1[11] = "";
                char *p = s1;
                for (j = 0; j < strlen(s); j++) {
                    if (j != i) { *(p++) = s[j]; }
                }
                permutation(s1);
            }
        }
    }
    这样是有问题的,不定义before以存储已排列过的部分,则每次递归,都只打印出当前层次未确定的字符的排列。因为对每一层递归来说,上一层递归只执行一次,也就是说这层递归无论有多少情况,上一层都只打印一次。这就造成了缺项。
    以 N=3 为例,以 1 为开头的全排列本该有两个,但是会出现 123 和 32 的结果,在第二个结果中1消失了,这是因为在递归中,处理第一位的操作只出现了一次。因此 N=3 的情况下,输出长度呈现 3 2 3 2 3 2 这样的情况。以上图的树来看,四个*的只输出一次,三个*输出4次,两个*输出12次,对应第一位被确定的情况下,第一位被打印出来的次数、第二位被打印出来的次数以及第三位的。
    同理,N=4的情况下,输出长度会呈现 4 3 2 2 4 3 2 2 …… 这样的情况。
    */
    
    
    //以下正文
    
    #include <stdio.h>
    #include <string.h>
    #include <malloc.h>
    
    /*定义了两个参数,s指的是待全排列的子串,before则保存是已排列过的部分,如1234,1243中的12即是已排列过的部分*/
    /*本质上说全排列是位置变动,而与具体的值无关,因此只需要稍微安排一下字符串(为了按字典序输出),就能放心地使用递归直接对子串全排列*/
    void permutation(char *s, char *before) {
        if (strlen(s) == 1) {
            int i;
            for (i = 0; i < strlen(before); i++) {
                printf("%c ", before[i]);
            }
            printf("%c
    ", s[0]);
        }
        else {
            int i;
            for (i = 0; i < strlen(s); i++) {
                int j;
                char newBefore[11] = "";		
              	/*这里之所以声明一个新的before是为了给每个下级递归分配独立的before避免冲突,事实上直接使用before会导致before一直增加元素直到数组溢出*/
                
              for (j = 0; j < strlen(before); j++) {
                    newBefore[j] = before[j];
                }
                newBefore[strlen(newBefore)] = s[i];
                char s1[11] = "";
                char *p = s1;
                for (j = 0; j < strlen(s); j++) {
                    if (j != i) { *(p++) = s[j]; }
                }
              	
              	/*对于每一次循环都进行一次递归调用,因为树的每个节点都有相同数量的子树,因此各自递归*/
                permutation(s1, newBefore);
            }
        }
    }
    
    
    int main() {
        char s[11] = "";
        int N;
        scanf("%d", &N);
        int i;
        for (i = 0; i < N; i++) {
            s[i] = (char) (i + '0' + 1);
        }
        char before[11] = "";
        permutation(s, before);
    
        return 0;
    }
    
    
  • 相关阅读:
    秋风下的萧瑟 NOIP2018 游记
    Dsu on Tree
    BZOJ 3812 : 主旋律
    FFT&NTT
    manacher
    Winniechen’s test1
    如何在万亿级别规模的数据量上使用Spark
    Spark运行时的内核架构以及架构思考
    hadoop离线数据存储和挖掘架构
    Hadoop平台的基本组成与生态系统
  • 原文地址:https://www.cnblogs.com/khunkin/p/10195470.html
Copyright © 2020-2023  润新知