WooKinson

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

 

题目描述:

 

代码如下:

  1 #include <stdio.h> 
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #define N  1000000
  5 #define HN 1000003
  6 #define LEN 9
  7 
  8 int head[HN],next[N]; 
  9 int st[N][LEN], goal[LEN];
 10 int dis[N];    //记录步数 
 11 
 12 int Hash(int *st)//获取本次排列组合的哈希值 
 13 {
 14     int i,v;
 15     v = 0;
 16     for (i=0 ; i<LEN ; i++)//得到一个LEN长度数值:v 
 17     {
 18         v = v*10 + st[i];
 19     }
 20     return v%HN;//得到对应哈希值 
 21 }
 22 
 23 
 24 // 功能:对本次的排列组合,若不在哈希表中,则在哈希表中进行键值映射 
 25 int try_insert(int rear)//rear:本次组合的编号 
 26 {
 27     int h = Hash(st[rear]);    //获得本次排列组合对应的哈希值 
 28     int u = head[h];        //根据哈希值,获得哈希表中对应的键(key),若没有则为0 
 29     
 30     while (u)//当上一步有拿到键(key),查找对应的值(value->排列组合), 
 31     {
 32         if (memcmp(st[u],st[rear],sizeof(st[0]))==0)//存在相同的值(value->排列组合) 
 33             return 0;    //本次值(value->排列组合)将不记录,退出 
 34         u = next[u];    //当前键(key)还有其他值,遍历获得其他值(value->排列组合)
 35     }
 36     
 37     //当前值(value->排列组合)不在哈希表中,将进行记录 
 38     next[rear] = head[h];    //当前键(key)的记录是否有其他值,若本身为新组合,为0;若为存在组合,则为其上一个编号(相同组合) 
 39     head[h] = rear;            //哈希表中对应的键(key),更新为本次组合编号(rear) 
 40     return 1;    
 41 }
 42 
 43 int bfs()
 44 {
 45     int d;
 46     int x,y,z,nx,ny,nz;
 47     int fron = 1,rear = 2;    //fron:当前排列组合;rear:移动后的排列组合 
 48     const int dir[4][2] = {{0,1},{0,-1},{1,0},{-1,0},};
 49     
 50     memset(head,0,sizeof(head));
 51     while (fron < rear)
 52     {
 53         if (memcmp(goal,st[fron],sizeof(st[0]))==0)//当前排列组合为目标排列组合 
 54             return fron; 
 55 
 56         for (z=0 ; z<LEN ; z++)
 57         {
 58             if (st[fron][z]==0)//0即为对应的'.' 
 59                 break;
 60         }
 61         
 62         x = z/3,y = z%3;//获得'.'的坐标 
 63         for (d=0 ; d<4 ; d++)
 64         {
 65             nx = x+dir[d][0];
 66             ny = y+dir[d][1];            
 67             if (nx>=0 && nx<3 && ny>=0 && ny<3)
 68             {
 69                 nz = 3*nx+ny;//'.'将要移动的下一步位置 
 70                                  
 71                 memcpy(&st[rear],&st[fron],sizeof(st[0]));                
 72                 st[rear][nz] = st[fron][z];
 73                 st[rear][z] = st[fron][nz];
 74                 
 75                 dis[rear] = dis[fron]+1;//记录步数 
 76                 if (try_insert(rear))//对新排列组合进行查找 
 77                     rear ++;//进队列 
 78             }
 79         }
 80         fron ++;//出队列 
 81     }
 82     
 83     return 0;
 84 }
 85 
 86 int main(void)
 87 {
 88     int i,ans;
 89     char s1[LEN+1],s2[LEN+1];
 90     memset(dis,0,sizeof(dis));
 91     scanf("%s%s",&s1,&s2);
 92     
 93     for (i=0 ; i<LEN ; i++)//将'.'转换为0,便于计算哈希值 
 94     {
 95         if (s1[i]=='.')
 96             st[1][i] = 0;
 97         else
 98             st[1][i] = s1[i]-'0';
 99             
100         if (s2[i]=='.')
101             goal[i] = 0;
102         else
103             goal[i] = s2[i]-'0';    
104     }    
105     
106     ans = bfs();
107     if (ans > 0)
108         printf("%d",dis[ans]);
109     else
110         puts("-1");
111     
112     return 0;
113 }
C解法

 

 

解题思路:

 本题要求最少步数转换成目标组合,广度优先遍历(BFS)可满足要求

每次对新组合进行检查时,需要较高的检索效率,

1.使用map或者set做检索时,其对应的检索效率低,超时不能满足题目需求;

2.对组合进行哈希判重,大大提高了检索效率;

 

关于本题的哈希判重,参考了:

https://blog.csdn.net/hao_zong_yin/article/details/62419919

https://www.cnblogs.com/acxblog/p/7253477.html

 

哈希判重,利用键-值映射,有效提高了搜索的效率;

1.建立键(key)表,head[NH],需初始化;建立值(value)表,next[N];

2.BFS搜索新组合,通过向不同方向移动 ' . ' (0)  得到新的组合;

3.根据新组合,计算对应的哈希值;

4.根据哈希值,进行检索决定是否添加新的排列组合

  4.1.插入的组合存在

   4.2.插入的组合不存在

 

5.若有新组合添加,队列+1(rear+1)

6.每次出列(fron+1),检查是否为目标组合

7.若fron > rear,则不存在方案,输出-1

 

posted on 2019-03-21 15:43  WooKinson  阅读(200)  评论(0编辑  收藏  举报