VJ- I - Eight II

***> 题目来源:***VJ- I - Eight II

Eight-puzzle, which is also called “Nine grids”, comes from an old
game.

In this game, you are given a 3 by 3 board and 8 tiles. The tiles are
numbered from 1 to 8 and each covers a grid. As you see, there is a
blank grid which can be represented as an ‘X’. Tiles in grids having a
common edge with the blank grid can be moved into that blank grid.
This operation leads to an exchange of ‘X’ with one tile.

We use the symbol ‘r’ to represent exchanging ‘X’ with the tile on its
right side, and ‘l’ for the left side, ‘u’ for the one above it, ‘d’
for the one below it.
在这里插入图片描述
The problem is to operate an operation list of ‘r’, ‘u’, ‘l’, ‘d’ to
turn the state of the board from state A to state B. You are required
to find the result which meets the following constrains:

  1. It is of minimum length among all possible solutions.
  2. It is the lexicographically smallest one of all solutions of minimum length. Input The first line is T (T <= 200), which means the
    number of test cases of this problem.

The input of each test case consists of two lines with state A
occupying the first line and state B on the second line. It is
guaranteed that there is an available solution from state A to B.
Output For each test case two lines are expected.

The first line is in the format of “Case x: d”, in which x is the case
number counted from one, d is the minimum length of operation list you
need to turn A to B. S is the operation list meeting the constraints
and it should be showed on the second line.

Sample Input
2
12X453786
12345678X
564178X23
7568X4123
Sample Output
Case 1: 2
dd
Case 2: 8
urrulldr

代码:

/**
 * bfs() + Cantor + 预处理 + 映射
 */
#include <bits/stdc++.h>
using namespace std;
const int inf = 1e8;
const int N = 4e5;
int n, m;
char End[9][10] = {"X12345678", "1X2345678", "12X345678",
                   "123X45678", "1234X5678", "12345X678",
                   "123456X78", "1234567X8", "12345678X"};

char step[] = "dlru"; // 字典序小的先遍历
int opx[4] = {1, 0, 0, -1};
int opy[4] = {0, -1, 1, 0};
int cantor[9] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320};
int vis[9][N]; // 标记走过的地方
int pre[9][N]; // 记录
struct node {
  int num[9]; //八位数
  int ok;     //状态(康托展开值)
  int pos;    // x的位置
};

// 计算cantor值
int Cantor(int *s) {
  int sum = 0;
  for (int i = 0; i < 9; i++) {
    int num = 0;
    for (int j = i + 1; j < 9; j++) {
      if (s[i] > s[j])
        num++;
    }
     sum += num * cantor[8 - i];
  }
  return sum;
}

void bfs(node x, int k) {
  queue<node> q;
  q.push(x);
  vis[k][x.ok] =
      1; //这个是初始化的值并不是真正走的值所以上面输出的时候是从倒数第二个开始输出
  while (!q.empty()) {
    node now = q.front();
    q.pop();

    int x = now.pos / 3;
    int y = now.pos % 3;
    for (int i = 0; i < 4; i++) {
      int xx = x + opx[i];
      int yy = y + opy[i];
      if (xx >= 0 && xx < 3 && yy >= 0 && yy < 3) {
        node next = now;
        swap(next.num[now.pos], next.num[xx * 3 + yy]);
        next.ok = Cantor(next.num);
        if (vis[k][next.ok] == -1) {
          next.pos = xx * 3 + yy;
          vis[k][next.ok] = i; //代表通过i方向的移动到达k这类中的v.ok状态
          pre[k][next.ok] = now.ok; //记录这种状态的前一种状态
          q.push(next);
        }
      }
    }
  }
}

void init(char *s, int k) {
  node u;
  for (int i = 0; i < 9; i++) {
    if (s[i] == 'X') {
      u.num[i] = 0;
      u.pos = i;
    } else
      u.num[i] = s[i] - '0';
  }
  u.ok = Cantor(u.num);
  bfs(u, k); // 每一种都bfs()
}

void printWay(int ok, int k) {
  string ans;
  while (ok != -1) {
    ans += step[vis[k][ok]];
    ok = pre[k][ok];
    //往上找
  }
  printf("%d\n", ans.size() - 1);
  for (int i = ans.size() - 2; i >= 0; i--) {
    printf("%c", ans[i]);
  }
  printf("\n");
}
int main(int argc, char const *argv[]) {
  char tmp[15]; // 用来映射
  int temp[N];
  memset(vis, -1, sizeof(vis)); // 初始化
  memset(pre, -1, sizeof(pre));
  for (int i = 0; i < 9; i++) {
    init(End[i], i);
  } // 全区来一遍
  int t;
  cin >> t;
  int cas = 0;
  while (t--) {
    char Start[10];
    scanf("%s", Start);
    int cnt = 1;
    int k;
    for (int i = 0; i < 9; i++) {
      if (Start[i] == 'X') {
        tmp[0] = 0;
        k = i;
      } else {
        tmp[Start[i] - '0'] = cnt++;
      }
    }
    char End[10];
    scanf("%s", End);
    for (int i = 0; i < 9; i++) {
      if (End[i] == 'X') {
        temp[i] = tmp[0];
      } else {
        temp[i] = tmp[End[i] - '0'];
      }
    }
    int ok = Cantor(temp);
    printf("Case %d: ", ++cas);
    printWay(ok, k);
  }
  return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值