zoukankan      html  css  js  c++  java
  • 【洛谷1379】八数码

    问题描述

    在3*3的九宫格棋盘中,摆有8个将牌,每个将牌上刻有1-8中的某一个数码。棋盘中留有一个空格,允许其四周的某一个将牌向空格移动,这样通过移动将牌就可以不断改变布局。给定一种初始布局,求变为目标布局所需的最少步数。

    目标布局为:

    1 2 3

    8 0 4

    7 6 5

    其中0表示空格。

    输入格式

    三行共9个数,表示初始布局

    输出格式

    一个整数表示变为目标布局的最少步数。若无解输出“no solution”

    样例输入

    0 1 3

    8 2 4

    7 6 5

    样例输出

    2

    题解

    从初始布局开始广搜。

    关键是状态的保存和判重比较麻烦。

    直接用3*3的形式保存肯定会爆的,考虑到一个状态只有九个数,可以把这九个数压缩成一个九位数,保存的问题就解决了。一个状态有九个格子,每个格子填一个数有9种填法(0~8),九个格子一共9!种填法,不超过4e5,队列开4e5就够了。

    接下来,怎么判重呢?如果每得出一个状态就和前面所有状态比较一遍,显然会TLE;如果用一个布尔数组来记录每种状态是否出现过,也要开876543210的数组,直接MLE了。由于最多只有9!种状态,其实只要标记这9!种状态有没有出现过就可以了。怎么把876543210压缩成9!呢?哈希!找个大质数,判断每个状态的模有没有出现过就行了。

     1e6+7是个很好的质数,本题用1e6+7作为哈希函数冲突不超过5个

     1 #include <cstdio>
     2 const int dx[10][5]={ {0,0,0,0,0},{2,2,4,0,0},{3,1,3,5,0},
     3                       {2,2,6,0,0},{3,1,5,7,0},{4,2,4,6,8},
     4                       {3,3,5,9,0},{2,4,8,0,0},{3,5,7,9,0},
     5                       {2,6,8,0,0}
     6                     };  //从右下角开始从下到上从右到左给九个格子编号,dx[i][0]表示和第i个格子相邻的格子的个数,dx[i][j](j>0)表示和第i个格子相邻的格子的编号
     7 const int ds[10]={1,10,100,1000,10000,1e5,1e6,1e7,1e8,1e9};
     8 const int inf=1e6+7,m=123804765;
     9 int f[1000005][5],q[400005][2],n;
    10 bool check(int x)
    11 {
    12     int s=x%inf;
    13     if (!f[s][0])
    14     {
    15         f[s][++f[s][0]]=x;
    16         return 1;
    17     }
    18     for (int i=1;i<=f[s][0];i++)
    19       if (f[s][i]==x)
    20         return 0;
    21     f[s][++f[s][0]]=x;
    22     return 1;
    23 }
    24 int getzero(int x)
    25 {
    26     int i,pre=x%10,s;
    27     if (!pre) return 1;
    28     for (i=2;i<=9;i++)
    29     {
    30         s=x%ds[i];
    31         if (s==pre) return i;
    32         pre=s;
    33     }
    34     return 9;
    35 }
    36 int bfs()
    37 {
    38     if (n==m) return 0;
    39     int h=0,t=1,i,j,k,x,y,s,u;
    40     q[1][1]=n;
    41     check(n);
    42     while (h!=t)
    43     {
    44         h++;
    45         u=q[h][1];
    46         x=getzero(u); 
    47         for (i=1;i<=dx[x][0];i++)
    48         {
    49             j=dx[x][i];
    50             y=(u/ds[j-1])%10;  
    51             s=u-y*ds[j-1]+y*ds[x-1];  
    52             if (check(s))
    53             {
    54                 if (s==m) return q[h][0]+1;
    55                 q[++t][1]=s;
    56                 q[t][0]=q[h][0]+1;
    57                 
    58             }
    59         }
    60         
    61     }
    62     return -1;
    63 }
    64 int main()
    65 {
    66     int i,j,x;
    67     /*for (i=1;i<=9;i++)
    68       scanf("%d",&x),
    69       n=n*10+x;*/
    70     scanf("%d",&n);  
    71     int ans=bfs();
    72     if (ans!=-1) printf("%d",ans);
    73     else printf("no solution");
    74     return 0;  
    75 }
  • 相关阅读:
    GitHub代码阅读神器,你值有拥有!
    SpringBoot项目构建成jar运行后,如何正确读取resource下的文件
    基于SpringBoot-Dubbo的微服务快速开发框架
    基于SpringBoot的Web API快速开发基础框架
    野蛮生长的前端,从杂牌军到正规军
    让Redis突破内存大小的限制
    myeclipse 8.5-10.0 安装 svn 方法
    几秒后刷新页面
    不错的Spring学习笔记(转)
    Spring学习笔记(三)-类扫描的注解
  • 原文地址:https://www.cnblogs.com/rabbit1103/p/9197908.html
Copyright © 2011-2022 走看看