zoukankan      html  css  js  c++  java
  • 九宫重拍(bfs + 康拓展开)

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

      我们把第一个图的局面记为:12345678.
      把第二个图的局面记为:123.46758
      显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
      本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
    输入格式
      输入第一行包含九宫的初态,第二行包含九宫的终态。
    输出格式
      输出最少的步数,如果不存在方案,则输出-1。
    样例输入
    12345678.
    123.46758
    样例输出
    3
    样例输入
    13524678.
    46758123.
    样例输出
    22
    ==========================分割线==================================
     
    这个题刚开始直接用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
    ", tmp);
    121 
    122     return 0;
    123 }
    View Code
  • 相关阅读:
    Random 种子问题
    Matrix issue
    Two sum.
    Best Time to Buy and Sell Stock
    Maximum difference between two elements
    二分查找法的实现和应用汇总
    Why you want to be restrictive with shrink of database files [From karaszi]
    Palindrome
    NetBeans vs Eclipse 之性能参数对比 [java060515]
    国内各大互联网公司相关技术站点不完全收录[转]
  • 原文地址:https://www.cnblogs.com/Howe-Young/p/4351882.html
Copyright © 2011-2022 走看看