---
title: The Rotation Game
tags:
  - Iterative Deepening A*
id: "1735"
categories:
  - - OI
    - Common Skill
date: 2018-01-14 16:25:59
---

## 题目描述

The rotation game uses a # shaped board, which can hold $24$ pieces of square blocks (see Fig.1). The blocks are marked with symbols 1, 2 and 3, with exactly $8$ pieces of each kind.

![](1.jpg)

Initially, the blocks are placed on the board randomly. Your task is to move the blocks so that the eight blocks placed in the center square have the same symbol marked. There is only one type of valid move, which is to rotate one of the four lines, each consisting of seven blocks. That is, six blocks in the line are moved towards the head by one block and the head block is moved to the end of the line. The eight possible moves are marked with capital letters A to H. Figure 1 illustrates two consecutive moves, move A and move C from some initial configuration.

## 题意概述

给定一个包含$24$个格子的井字形棋盘，其中恰有$8$个 1、$8$个 2 和$8$个 3。要求通过$8$种操作使得中间八个格子上的数字相同。求在操作数最小的情况下字典序最小的操作方案。

## 算法分析

如果用三进制表示状态进行 BFS，那么空间肯定不够。这时可以用时间换空间，进行 IDA\*。有两个剪枝：不进行上次操作的逆操作；无论如何也不能在规定深度内完成时直接退出。

## 代码

```cpp
#include <cstdio>

int max(int a, int b) {
  return a > b ? a : b;
}

static const int TAR[] = { 6, 7, 8, 11, 12, 15, 16, 17 };
static const int OPER[][7] = {
  { 0,   2,   6,   11,  15,  20,  22 },
  { 1,   3,   8,   12,  17,  21,  23 },
  { 10,  9,   8,   7,   6,   5,   4 },
  { 19,  18,  17,  16,  15,  14,  13 },
  { 23,  21,  17,  12,  8,   3,   1 },
  { 22,  20,  15,  11,  6,   2,   0 },
  { 13,  14,  15,  16,  17,  18,  19 },
  { 4,   5,   6,   7,   8,   9,   10 }
};
int limit, cnt[3], a[24], o[200];

int get_h() {
  cnt[0] = cnt[1] = cnt[2] = 0;
  for (int i = 0; i < 8; ++ i) ++ cnt[a[TAR[i]] - 1];
  return 8 - max(cnt[0], max(cnt[1], cnt[2]));
}

bool is_inv(int a, int b) {
  if (a > b) a ^= b ^= a ^= b;
  return (a == 0 && b == 5) || (a == 1 && b == 4) || (a == 2 && b == 7) || (a == 3 && b == 6);
}

bool dfs(int t, int last) {
  if (t == limit) return ! get_h();
  if (t + get_h() > limit) return false;
  for (int i = 0; i < 8; ++ i)
    if (! ~ last || ! is_inv(last, i)) {
      int tmp = a[OPER[i][0]];
      for (int j = 0; j < 6; ++ j) a[OPER[i][j]] = a[OPER[i][j + 1]];
      a[OPER[i][6]] = tmp, o[t] = i;
      if (dfs(t + 1, i)) return true;
      tmp = a[OPER[i][6]];
      for (int j = 6; j; -- j) a[OPER[i][j]] = a[OPER[i][j - 1]];
      a[OPER[i][0]] = tmp;
    }
  return false;
}

int main() {
  while (scanf("%d", &a[0]), a[0]) {
    for (int i = 1; i < 24; ++ i) scanf("%d", &a[i]);
    for (limit = 0; ; ++ limit)
      if (dfs(0, -1)) {
        if (limit) for (int i = 0; i < limit; ++ i) printf("%c", 'A' + o[i]);
        else printf("No moves needed");
        printf("\n%d\n", a[6]); break;
      }
  }
  return 0;
}
```
