[算法竞赛入门经典] UVa1343 旋转游戏 完全注释

 

// UVa1343 The Rotation Game
// Rujia Liu
// This solutions uses IDA* instead of BFS described in the book, because it's shorter 8-)
// It's shorter because no need for lookup tables and "automatically" lexicographically smallest solution.
#include<cstdio>
#include<algorithm>
using namespace std;

// 每个格子对应的index
/*
      00    01
      02    03
04 05 06 07 08 09 10
      11    12
13 14 15 16 17 18 19
      20    21
      22    23
*/

// lines E~H are computed with the help of rev[]
// 4条 8个方向 7个数
int line[8][7]={
  { 0, 2, 6,11,15,20,22}, // A
  { 1, 3, 8,12,17,21,23}, // B
  {10, 9, 8, 7, 6, 5, 4}, // C
  {19,18,17,16,15,14,13}, // D
};

//每个方向对应的反方向
const int rev[8] = {5, 4, 7, 6, 1, 0, 3, 2}; // reverse lines of each line

// center squares
// 题目要求的八个中心格子对应的index
const int center[8] = {6, 7, 8, 11, 12, 15, 16, 17};

// 总共24个数
int a[24];
// ans记录每步的移动方向(A、B、C...H)
char ans[1000];

//八个中心格子是不是都相等
bool is_final() {
  for(int i = 0; i < 8; i++)
    if (a[center[i]] != a[center[0]]) return false;
  return true;
}

// target只会取 1 2 3 (棋盘上只有这三个数)
int diff(int target) {
  int ans = 0;
  for(int i = 0; i < 8; i++)
    if(a[center[i]] != target) ans++;
  return ans;
}

// 从当前状态来看,达到目的状态至少要多少步
inline int h() {
  return min(min(diff(1), diff(2)), diff(3));
}

inline void move(int i) {
  int tmp = a[line[i][0]];
  for(int j = 0; j < 6; j++) a[line[i][j]] = a[line[i][j+1]];
  a[line[i][6]] = tmp;
}

bool dfs(int d, int maxd) {
  if(is_final()) {
    ans[d] = '\0';
    printf("%s\n", ans);
    return true;
  }
  // 剪枝
  if(d + h() > maxd) return false;
  for(int i = 0; i < 8; i++) {
    ans[d] = 'A' + i;
    move(i);
    if(dfs(d+1, maxd)) return true;
    // move(rev[i])能恢复现场!?不是引用啊
    // 可以先memcpy(tmp, line[i], sizeof(line[i])保存现场
    // 然后在这里memcpy(line[i], tmp, sizeof(line[i])恢复现场
    move(rev[i]);
  }
  return false;
}

int main() {
  for(int i = 4; i < 8; i++)
    for(int j = 0; j < 7; j++) line[i][j] = line[rev[i]][6-j];

  while(scanf("%d", &a[0]) == 1 && a[0]) {
    for(int i = 1; i < 24; i++) scanf("%d", &a[i]);
    for(int i = 0; i < 24; i++) if(!a[i]) return 0;
    if(is_final()) {
      printf("No moves needed\n");
    } else {
      for(int maxd = 1; ; maxd++)
        if(dfs(0, maxd)) break;
    }
    //输出中间8个格子都是啥数
    //上面还有个printf,输出每步的方向
    printf("%d\n", a[6]);
  }
  return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值