九宫重拍(bfs + 康拓展开)

问题描述   如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。

《九宫重拍(bfs + 康拓展开)》
《九宫重拍(bfs + 康拓展开)》

  我们把第一个图的局面记为:12345678.

  把第二个图的局面记为:123.46758

  显然是按从上到下,从左到右的顺序记录数字,空格记为句点。

  本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。 输入格式   输入第一行包含九宫的初态,第二行包含九宫的终态。 输出格式   输出最少的步数,如果不存在方案,则输出-1。 样例输入 12345678.

123.46758 样例输出 3 样例输入 13524678.

46758123. 样例输出 22 ==========================分割线==================================   这个题刚开始直接用bfs去做,但是开的标记数组的维数会非常高,后来才在网上看到用康拓展开,能用到
康拓展开是因为这可以看成是一个序列,所以可以用康拓展开求出他在全排列中的次序,这样标记数组就可以开一维的了,这道题的广搜和
三个水杯那个题差不多 代码如下:
《九宫重拍(bfs + 康拓展开)》
《九宫重拍(bfs + 康拓展开)》

  1 #include<iostream>
  2 #include <cstdio>
  3 #include <queue>
  4 #include <cstring>
  5 using namespace std;
  6 typedef long long LL;
  7 struct Node{
  8     int cur[9];
  9     LL step;
 10 };
 11 Node s, e;
 12 const int N = 1e6;
 13 const int Next[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};//搜索的四个方向
 14 bool vis[N * 4];//标记数组
 15 int fac[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};//前几个数的阶乘
 16 LL cantor(int s[])//康拓展开
 17 {
 18     LL ans = 0;
 19     int n = 9;
 20     for (int i = 0; i < n - 1; i++)
 21     {
 22         int tmp = 0;
 23         for (int j = i + 1; j < n; j++)
 24             if (s[j] < s[i])
 25                 tmp++;
 26         ans += fac[n - i - 1] * tmp;
 27     }
 28     return ans;
 29 }
 30 void cantor_reverse(int index, int a[])//康拓展开逆, 在本道题中未使用
 31 {
 32     index--;
 33     int n = 9;
 34     bool visit[9];
 35     memset(visit, false, sizeof(visit));
 36     for (int i = 0; i < n; i++)
 37     {
 38         int tmp = index / fac[n - i - 1];
 39         for (int j = 0; j <= tmp; j++)
 40             if (visit[j])
 41                 tmp++;
 42         a[i] = tmp + 1;
 43         visit[tmp] = true;
 44         index %= fac[n - i - 1];
 45     }
 46 }
 47 bool ischecked(int row, int col)//检查是否满足移动的条件
 48 {
 49     return (row > 0 && col > 0 && row < 4 && col < 4);
 50 }
 51 bool matched(Node node)//看是否达到给定的状态
 52 {
 53     for (int i = 0; i < 9; i++)
 54         if (node.cur[i] != e.cur[i])
 55             return false;
 56     return true;
 57 }
 58 LL bfs()
 59 {
 60     memset(vis, false, sizeof(vis));
 61     queue<Node> Q;
 62     s.step = 0;
 63     Q.push(s);
 64     Node p, q;
 65     int start_num = cantor(s.cur);
 66     vis[start_num] = true;//标记第一个元素
 67     while (!Q.empty())
 68     {
 69         p = Q.front();
 70         Q.pop();
 71         int pos;
 72         for (pos = 0; pos < 9; pos++)
 73             if (p.cur[pos] == 9)//将"."当成9来计算
 74                 break;
 75         int row, col, new_row, new_col;
 76         row = pos / 3 + 1;
 77         col = pos % 3 + 1;
 78         for (int i = 0; i < 4; i++)
 79         {
 80             new_row = row + Next[i][0];
 81             new_col = col + Next[i][1];
 82             if (ischecked(new_row, new_col))//判断是否满足可移动的条件
 83             {
 84                 q = p;
 85                 q.step = p.step + 1;
 86                 //下面三步是交换这两个数(也就是移动到空位去)
 87                 int t = q.cur[(row - 1) * 3 + col - 1];
 88                 q.cur[(row - 1) * 3 + col - 1] = q.cur[(new_row - 1) * 3 + new_col - 1];
 89                 q.cur[(new_row - 1) * 3 + new_col - 1] = t;
 90                 if (matched(q))//如果找到之后直接返回
 91                 {
 92                     return q.step;
 93                 }
 94                 int num = cantor(q.cur);
 95                 if (!vis[num])
 96                 {
 97                     vis[num] = true;
 98                     Q.push(q);
 99                 }
100             }
101         }
102     }
103     return -1;//找不到就返回-1
104 }
105 int main()
106 {
107     char sta[10], en[10];
108     scanf("%s %s", sta, en);
109     for (int i = 0; i < 9; i++)
110         if (sta[i] != '.')
111             s.cur[i] = sta[i] - '0';
112         else
113             s.cur[i] = 9;//将'.'看成9
114     for (int i = 0; i < 9; i++)
115         if (en[i] != '.')
116             e.cur[i] = en[i] - '0';
117         else
118             e.cur[i] = 9;
119     LL tmp = bfs();
120     printf("%lld\n", tmp);
121 
122     return 0;
123 }

View Code

 

    原文作者:Howe_Young
    原文地址: https://www.cnblogs.com/Howe-Young/p/4351882.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞