zoukankan      html  css  js  c++  java
  • 排列的逆

    将排列(abcdef)应用(cdfbea),那么它的逆为(cdfbea)应用(abcdef)等价于(abcdef)应用(fdabec)

    所以(cdfbea)的逆为(fdabec)

    算法A流程

      E1.获取当前的替代X,X[i]表示i被X[i]代替,将m从1到n遍历(全部遍历,与起始点无关),设j为任意负值.

      E2.获取当前的i=X[m],如果当前X[m]<0,则X[m]取自身相反数,去E5.

      E3.当前X[m]大于0,X[m]=j,j=-m,m=i,i=X[m].

      E4.i>0,则回E3;否则将X[m]=-j;

      E5.m自增加1.如果m>n,算法结束.

    证明

      某排列的逆可以分为1~n个部分,每个部分可以看作一个环.通过遍历,对于每个点所在的环,要么已经遍历过要么没有遍历过,对于没有遍历过的,一开始这个环上的某个节点会获得一个任意的负值(j),然后将当前的-m赋给X[X[m]],由于是环路最终一定存在X[X[m]]=j。而这个过程中所有-m均赋值给X[X[m]],只有最后一个-m没有赋值,而恰好这个-m是我们一开始遍历这个环的某个节点的最终值,同时在这个过程中,这个环路上其他的节点都已经赋过值,因此对于没有遍历过的环上的节点只要先处理一个节点,其他节点的值就会随之计算出来。

    代码实现

    void PermutationInvertingA(char *SrcStr)
    {
        int m,Len,i,j;
        Len=strlen(SrcStr);
        int *X=(int *)malloc((Len+1)*sizeof(int));
        for(i=0;i<Len;++i)
        {
            X[i+1]=SrcStr[i]-'a'+1;
        }
        for(m=1,j=-1;m<=Len;++m)
        {
            i=X[m];
            if(i<0)
            {
                X[m]=-i;
                continue;
            }
            if(i==m)
            {
                continue;
            }
            while(i>0)
            {
                X[m]=j;
                j=-m;
                m=i;
                i=X[m];
            }
            X[m]=-j;
        }
        for(i=1;i<=Len;++i)
        {
            printf("%d ",X[i]);
        }
        printf("
    ");
        free(X);
    }
    View Code

     算法B流程

      E1.获取当前的X[i],X[i]表示i要被X[i]代替,然后将所有的X[i]=-X[i],将m从1到n开始遍历(全部遍历,与起始点无关)

      E2.将m赋给j

      E3.i=X[j],如果i>0,将j=i,重复E3.

      E4.X[j]=X[-i],X[-i]=m

      E5.m自增加1,如果m>n算法结束

    证明

      撤销操作不同环之间的操作是不影响,所以我们只需要看一个环就行,假设当前X[i](1<=i<=n)为

      X[1]=-3,X[2]=-1,X[3]=-4,X[4]=-2(环为1->3->4->2->1)

      具体流程就为:

      将1指向的操作撤销,将X[3]原值赋给X[1],X[3]=1

      得到X[1]=-4,X[2]=-1,X[3]=1,X[4]=-2

      将2指向的操作撤销,X[2]=-4,X[1]=2

      得到X[1]=2,X[2]=-4,X[3]=1,X[4]=-2

      将3指向的操作撤销,由于当前X[3]为正数,根据X[3]当前的值找到了X[1],因为X[3]的原值赋给了X[1],然后有找到了X[2],就有X[2]=-2,X[4]=3

      得到X[1]=2,X[2]=-2,X[3]=1,X[4]=3

      将4指向的操作撤销,先找X[4],然后找X[3],然后找X[1],然后找X[2],就有X[2]=-2,X[2]=4

      得到X[1]=2,X[2]=4,X[3]=1,X[4]=3

      算法每一次是为了撤销当前的数指向的操作,然后逐步构造出最终的图(排列)

    代码实现

    void PermutationInvertingB(char *SrcStr)
    {
        int m,Len,i,j;
        Len=strlen(SrcStr);
        int *X=(int *)malloc((Len+1)*sizeof(int));
        for(i=0;i<Len;++i)
        {
            X[i+1]=-(SrcStr[i]-'a'+1);
        }
        for(m=0;m<=Len;++m)
        {
            j=m;
            while(i=X[j],i>0)
            {
                j=i;
            }
            X[j]=X[-i];
            X[-i]=m;
        }
        for(i=1;i<=Len;++i)
        {
            printf("%d ",X[i]);
        }
        printf("
    ");
        free(X);
    }
    View Code
  • 相关阅读:
    多线程学习
    Redis学习2
    Redis学习1
    封装
    创建对象内存分析
    稀疏数组
    反转数组、冒泡排序
    可变参数
    .net core 3.x Web Api + Docker个人练手项目
    .net 性能优化手段
  • 原文地址:https://www.cnblogs.com/NoSoul/p/3304111.html
Copyright © 2011-2022 走看看