zoukankan      html  css  js  c++  java
  • [知识点]Cantor展开

    // 此博文为迁移而来,写于2015年3月14日,不代表本人现在的观点与看法。原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vtyo.html

    1、含义
           一个很简单的概念哈,其实它的本质就是将你当前状态压缩成一个数,且状态与数一一对应,故一般用在哈希判重,因为有时哈希判重会存不下,或者根本不可能。这是一项辅助的知识点,故不详解。
     
    2、公式
           X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0,其中,a[i]为整数,并且0<=a[i]<=i<=n。a[i]的意义参见举例中的解释部分。
           举例
           例如,3 5 7 4 1 2 9 6 8 展开为 98884。因为X=2*8!+3*7!+4*6!+2*5!+0*4!+0*3!+2*2!+0*1!+0*0!=98884.
           排列的第一位是3,比3小的数有两个,以这样的数开始的排列有8!个,因此第一项为2*8! 排列的第二位是5,比5小的数有1、2、3、4,由于3已经出现,因此共有3个比5小的数,这样的排列有7!个,因此第二项为3*7!
    以此类推,直至0*0!。
     
    3、例题
           很好理解的东西我们就直接通过例题来看如何实现。
    -------------------------------------------------------------------------------------------------------
    数字矩阵(number)
     
    问题描述
    还别说ZZD平常毛毛躁躁的,考场上的他可毫不含糊,孤身闯阵,奋勇杀敌,多般神勇,一鼓作气地攻下了第一题,第二题,第三题,真可谓一夫当关,万夫莫开啊!当下正浩浩荡荡地朝第四题前进呢。但是,敌人也不是吃干饭的,经受了一二三题的失败后,他们摸清了一个事实,那就是ZZD率领的银河站队所摆的战阵------银河九宫阵(指横、竖和对角线上的战士战斗力之和都等于15的九宫格,每个格子中的数都在1~9之间,并且不重复)非常厉害,所以在第三题之后他们就对这种战阵进行了超强的光子干扰,也就是使阵中每个战士的战斗资料相互间打乱,这样就让战阵的战斗力大打折扣。难怪刚才刷第四题的时候特别困难,ZZD恍然大悟。而他只会领兵作战,至于修复资料的工作自然就叫给了变成天才的你来解决。所以你只需告诉ZZD资料最少移动的步数(指战斗值上下或左右相交换),如果怎么移动都无法恢复战阵,则输出-1。
     
    输入文件(number.in)
    一共有50个战阵给你修复;
    每个战阵用一个3*3的数字矩阵表示,每一个数表示一个战士的战斗值;
    相邻两个数字距阵不用空行隔开。
     
    输出文件(number.out)
    应该有50行,每行对应一个距阵修复的最少步数,如无法修复,则为-1。
     
    输入样例:
    1 5 2
    6 9 3
    8 4 7
    1 8 6
    4 2 3
    9 5 7
    5 1 9
    4 8 3
    2 7 6
     
    输出样例
    5
    6
    6
     
    样例说明
    样例就只给出3个供大家参考啦!
    -----------------------------------------------------------------------------------------------------
    题解:这道题是搜索题,但是不是直接暴搜就搜得到的。不难看出,这道题如果不在BFS的过程中用哈希判重,那么将会爆栈。但是,我们总不可能用九维数组来存hash吧?正如今天的主题一样,在哈希判重时,它需要用到康拓展开。康拓展开为什么能够在这里使用?因为对于栈内每一个矩阵,都有且仅有1-9这9个数字且不重复,所以康拓展开式和矩阵一一对应,可以很方便的判重了。
     
    代码:
    #include<cstdio>
    #include<cstring>
    #define MAXN 100005
     
    const int JC[9]={0,1,2,6,24,120,720,5040,40320};
    struct Queue
    {
      int map[4][4],dep;
    };
    Queue q[MAXN]; 
    int hash[3628810];
     
    void Copy(int head,int tail)
    {
      for (int i=1;i<=3;i++)
        for (int j=1;j<=3;j++)
          q[tail].map[i][j]=q[head].map[i][j];
    }
     
    void Swap(int x1,int y1,int x2,int y2,int tail)
    {
      int temp;
      temp=q[tail].map[x1][y1];
      q[tail].map[x1][y1]=q[tail].map[x2][y2];
      q[tail].map[x2][y2]=temp;
    }
     
    int Cantor(int tail)
    {
      int count[10],ans=0,now=8,tot=0,temp[10];
      memset(count,0,sizeof(count));
      for (int i=1;i<=3;i++)
        for (int j=1;j<=3;j++)
        {
          tot++;
          temp[tot]=q[tail].map[i][j];
        }
      for (int i=1;i<=8;i++)
      {
        for (int j=i+1;j<=9;j++)
          if (temp[i]>temp[j]) count[now]++;
        ans+=JC[now]*count[now];
        now--;
      }
      return ans;
    }
     
    int Check(int tail)
    {
      if (q[tail].map[1][1]+q[tail].map[1][2]+q[tail].map[1][3]!=15) return 0;
      if (q[tail].map[2][1]+q[tail].map[2][2]+q[tail].map[2][3]!=15) return 0;
      if (q[tail].map[3][1]+q[tail].map[3][2]+q[tail].map[3][3]!=15) return 0;
      if (q[tail].map[1][1]+q[tail].map[2][1]+q[tail].map[3][1]!=15) return 0;
      if (q[tail].map[1][2]+q[tail].map[2][2]+q[tail].map[3][2]!=15) return 0;
      if (q[tail].map[1][3]+q[tail].map[2][3]+q[tail].map[3][3]!=15) return 0;
      if (q[tail].map[1][1]+q[tail].map[2][2]+q[tail].map[3][3]!=15) return 0;
      if (q[tail].map[3][1]+q[tail].map[2][2]+q[tail].map[1][3]!=15) return 0;
      return 1;
    }
     
    int BFS()
    {
      int head=1,tail=2;
      while (head!=tail)
      {
        for (int i=1;i<=2;i++)
          for (int j=1;j<=3;j++)
          {
            Copy(head,tail);
            Swap(i,j,i+1,j,tail);
            int NowCantor=Cantor(tail);
            if (hash[NowCantor]!=1)
            {
              hash[NowCantor]=1;
              q[tail].dep=q[head].dep+1;
              if (Check(tail)==1) return q[tail].dep;
              tail++;
            }
          }
        for (int i=1;i<=3;i++)
          for (int j=1;j<=2;j++)
          {
            Copy(head,tail);
            Swap(i,j,i,j+1,tail);
            int NowCantor=Cantor(tail);
            if (hash[NowCantor]!=1)
            {
              hash[NowCantor]=1;
              q[tail].dep=q[head].dep+1;
              if (Check(tail)==1) return q[tail].dep;
              tail++;
            }
          }
        head++;
      }
      return -1;
     
    int main()
    {
      freopen("number.in","r",stdin);
      freopen("number.out","w",stdout);
      for (int t=1;t<=50;t++)
      {
        for (int i=1;i<=3;i++)
          for (int j=1;j<=3;j++)
            scanf("%d",&q[1].map[i][j]);
        printf("%d ",BFS());
        memset(hash,0,sizeof(hash));
      }
      return 0;
    }
  • 相关阅读:
    通过docker把本地AspNetCore WebAPI镜像打包到阿里云镜像仓库并在centos部署
    记一次Java AES 加解密 对应C# AES加解密 的一波三折
    .Net Core MVC实现自己的AllowAnonymous
    Net Core 中间件实现修改Action的接收参数及返回值
    手把手教你实现自己的abp代码生成器
    C# 实现Jwtbearer Authentication
    vs2017调试浏览器闪退
    ABP 邮箱设置
    FastJson反序列化获取不到值
    内网环境下搭建maven私服小技巧
  • 原文地址:https://www.cnblogs.com/jinkun113/p/4677226.html
Copyright © 2011-2022 走看看