POJ 1077 Eight

题目链接:POJ 1077【Eight】



思路

       将X看作9,本题可以视为1-9的全排列所以使用康拓展开作为哈希函数。所以结构体使用pre存储前一个状态的下标,number存储当前状态在结构体数组中的下标,oper存储上一个状态到当前状态的操作,zeroSite记录当前状态下0的位置,state存储当前状态的哈希函数值,num数组存储当前状态下的八码图其中x用9代替。
       所以在输入时需要对输入的数据进行特判处理,找出x的位置,并将x用9代替。然后BFS就是一个常规的BFS,中间关于x的移动判断和操作的上下左右需要特殊判断一下,如果移动后出现没出现过的新状态则,将新状态放入结构体数组中并加入队列继续搜索,直到出现一个和结果相同的状态,此时就利用pre,不断回溯查找上一个状态的下标,并存储,最后按顺序输出。


代码

#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
#define ll long long
const int N = 5e5 + 10;
#define target 0

struct eight {
  int pre;
  int number;
  char oper;
  int zeroSite;
  int state;
  int num[10];
} puzzle[N], start;


int h[10]={1,1,2,6,24,120,720,5040,40320,362880};
int cnt = 0, dir[5] = {1, -1, 3, -3};
bool vis[N];

// 康拓展开
int cantor(struct eight a) {
  int res = 0, fac = 1;
  for (int i = 1; i < 9; i++) {
    int temp = 0;
    for (int j = i + 1; j <= 9; j++) {
      if (a.num[i] > a.num[j]) temp++;
    }
    res += temp * h[9 - i];
  }
  return res;
}

// 判断x是否可以做出dir的移动
bool check(int x, int dir) {
  if (dir == -1 && (x == 1 || x == 4 || x == 7))
    return false;
  if (dir == 1 && (x == 3 || x == 6 || x == 9))
    return false;
  if (dir == -3 && (x == 1 || x == 2 || x == 3))
    return false;
  if (dir == 3 && (x == 7 || x == 8 || x == 9))
    return false;
  return true;
}

// 回溯操作,并存储输出
void print(int x) {
  int store[N], cnt = 0;
  while (x) {
    store[++cnt] = x;
    x = puzzle[x].pre;
  }

  for (int i = cnt; i >= 1; i--) {
    cout << puzzle[store[i]].oper;
  }
  cout << endl;
}

void bfs() {
  vis[start.state] = true;
  queue<struct eight> q;
  q.push(start);

  int num = 0;
  while (!q.empty()) {
    struct eight now = q.front();
    q.pop();

    if (now.state == target) {
      print(now.number);
      return;
    }

    for (int i = 0; i < 4; i++) {
      struct eight dnow = now;
      if (check(dnow.zeroSite, dir[i])) {
        swap(dnow.num[dnow.zeroSite], dnow.num[dnow.zeroSite + dir[i]]);
        dnow.zeroSite += dir[i];
        dnow.state = cantor(dnow);
        if (vis[dnow.state] == true)
          continue;
        dnow.pre = now.number;
        dnow.number = cnt;
        if (i == 0) {
          dnow.oper = 'r';
        } else if (i == 1) {
          dnow.oper = 'l';
        } else if (i == 2) {
          dnow.oper = 'd';
        } else {
          dnow.oper = 'u';
        }
        puzzle[cnt++] = dnow;
        vis[dnow.state] = true;
        q.push(dnow);
      }
    }
  }
  cout << "unsolvable" << endl;
}

int main() {
  memset(vis, 0, sizeof vis);
  for (int i = 1; i <= 9; i++) {
    char s;
    cin >> s;
    if (s == 'x') {
      start.num[i] = 9;
      start.zeroSite = i;
    } else {
      start.num[i] = s - '0';
    }
  }

  start.pre = -1;
  start.number = cnt;
  puzzle[cnt++] = start;
  start.state = cantor(start);

  bfs();
  return 0;
}
posted @ 2024-07-11 16:25  薛定谔的AC  阅读(1)  评论(0编辑  收藏  举报