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 @   薛定谔的AC  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示