这个8数码是绕成一圈的
单组组输入
所以我们来一组搜一次
这里给出bfs和A*
A*的话,你可以使用曼哈顿距离
IDA*的话,用曼哈顿距离
bfs
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const char direct[4] = { 'u','d','l','r' };
const int dir[4][2] = { {-1,0},{1,0},{0,-1},{0,1} }, N = 362880;
const int aim = 46685;
//const int aim = 46233;
const int n = 9;
bool visit[N];
//阶乘
const int fac[n] = { 1,1,2,6,24,120,720,5040,40320 };
//康托展开
int cantor(int s[]) {
int result = 0, cnt = 0;
for (int i = 0; i < n - 1; ++i) {
cnt = 0;
for (int j = i + 1; j < n; ++j) {
if (s[i] > s[j])++cnt;
}
result += fac[n - 1 - i] * cnt;
}
return result;
}
//逆康托展开
void reverseCantor(int hash, int s[], int &space) {
bool visited[n] = {};
int temp;
for (int i = 0; i < n; ++i) {
temp = hash / fac[n - 1 - i];
for (int j = 0; j < n; ++j) {
if (!visited[j]) {
if (temp == 0) {
s[i] = j;
if (j == 0)space = i;
visited[j] = true;
break;
}
--temp;
}
}
hash %= fac[8 - i];
}
}
void bfs(int start) {
typedef pair<int, int> P;
queue<P> q;
q.push(P(start, 0));
visit[start] = true;
int state[n], space;
while (!q.empty()) {
P t = q.front();
q.pop();
int preHash = t.first;
int step = t.second + 1;
reverseCantor(preHash, state, space);
for (int i = 0; i < 4; ++i) {
int tx = space / 3 + dir[i][0];
int ty = space % 3 + dir[i][1];
if (tx < 0 || tx>2 || ty < 0 || ty>2)continue;
int tz = tx * 3 + ty;
state[space] = state[tz];
state[tz] = 0;
int hash = cantor(state);
if (!visit[hash]) {
if (hash == aim) {
printf("%d\n", step);
return;
}
visit[hash] = true;
q.push(P(hash, step));
}
state[tz] = state[space];
state[space] = 0;
}
}
}
int main() {
char x;
int a[n];
for (int i = 0; i < n; ++i) {
scanf("%c", &x);
a[i] = x - '0';
}
int hash = cantor(a);
if (hash == aim)printf("0\n");
else bfs(hash);
return 0;
}
A*
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<cmath>
using namespace std;
const int dir[4][2] = { {-1,0},{1,0},{0,-1},{0,1} }, N = 362880;
const int aim = 46685;
const int n = 9;
bool visit[N];
int goal_state[9][2] = {
{0, 0}, {0, 1}, {0, 2},
{1, 2}, {2, 2}, {2, 1},
{2, 0}, {1, 0}, {1, 1}
};
//阶乘
const int fac[n] = { 1,1,2,6,24,120,720,5040,40320 };
//康托展开
int cantor(int s[]) {
int result = 0, cnt = 0;
for (int i = 0; i < n - 1; ++i) {
cnt = 0;
for (int j = i + 1; j < n; ++j) {
if (s[i] > s[j])++cnt;
}
result += fac[n - 1 - i] * cnt;
}
return result;
}
//逆康托展开
void reverseCantor(int hash, int s[], int &space) {
bool visited[n] = {};
int temp;
for (int i = 0; i < n; ++i) {
temp = hash / fac[n - 1 - i];
for (int j = 0; j < n; ++j) {
if (!visited[j]) {
if (temp == 0) {
s[i] = j;
if (j == 0)space = i;
visited[j] = true;
break;
}
--temp;
}
}
hash %= fac[8 - i];
}
}
//f=g+h
int g[N];
int h(int s[]) {
int k, result = 0;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
k = i * 3 + j;
if (s[k] == 0)continue;
result += abs(1.0*(i - goal_state[s[k] - 1][0])) + abs(1.0*(j - goal_state[s[k] - 1][1]));
}
}
return result;
}
class Chess {
public:
int hash, f;
Chess(const int &hash, const int &f) :hash(hash), f(f) {}
bool operator <(const Chess &t)const {
if (f == t.f)return g[hash] > g[t.hash];
return f > t.f;
}
};
//A*算法
void A_star(int start, int f) {
priority_queue<Chess> q;
q.push(Chess(start, f));
int preHash, hash, state[n], space, preH;
while (!q.empty()) {
//取出节点
Chess preChess = q.top();
preHash = preChess.hash;
if (preHash == aim) {
printf("%d\n", g[preHash]);
return;
}
q.pop();
preH = preChess.f - g[preHash];
reverseCantor(preHash, state, space);
for (int i = 0; i < 4; ++i) {
int tx = space / 3 + dir[i][0];
int ty = space % 3 + dir[i][1];
if (tx < 0 || tx>2 || ty < 0 || ty>2)continue;
int tz = 3 * tx + ty;
state[space] = state[tz];
state[tz] = 0;
hash = cantor(state);
//没访问过
if (!visit[hash]) {
g[hash] = g[preHash] + 1;
visit[hash] = true;
q.push(Chess(hash, g[hash] + h(state)));
}
//访问过了,但是从preHash走一步到hash比直接走到hash更短
else if (g[preHash] + 1 < g[hash]) {
g[hash] = g[preHash] + 1;
q.push(Chess(hash, g[hash] + preH));
}
state[tz] = state[space];
state[space] = 0;
}
}
}
int getInv(int s[]) {
int cnt = 0;
for (int i = 1; i < n; ++i) {
if (s[i] == 0)continue;
for (int j = 0; j < i; ++j) {
if (s[j] == 0)continue;
if (s[i] < s[j])
++cnt;
}
}
return cnt & 1;
}
int main() {
char x;
int a[n];
for (int i = 0; i < n; ++i) {
scanf("%c", &x);
a[i] = x - '0';
}
int hash = cantor(a);
visit[hash] = true;
g[hash] = 0;
A_star(hash, h(a));
return 0;
}
IDA*
#include<iostream>
#include<cstdio>
using namespace std;
const char direct[4] = { 'u','d','l','r' };
const int dir[4][2] = { {-1,0},{1,0},{0,-1},{0,1} }, N = 362880;
const int n = 9;
bool flag;
int a[n];
char step[32];
int maxDeep;
int goal_state[9][2] = {
{0, 0}, {0, 1}, {0, 2},
{1, 2}, {2, 2}, {2, 1},
{2, 0}, {1, 0}, {1, 1}
};
int abs(int a, int b) {
if (a > b)return a - b;
return b - a;
}
int h() {
int k, result = 0;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
k = i * 3 + j;
if (a[k] == 0)continue;
result += abs(i, goal_state[a[k] - 1][0]) + abs(j, goal_state[a[k] - 1][1]);
}
}
return result;
}
bool reverse(char a, char b) {
return (a == 'u'&& b == 'd')
|| (a == 'd'&& b == 'u')
|| (a == 'l'&& b == 'r')
|| (a == 'r'&&b == 'l');
}
int dfs(int deep, int space) {
int t = h(), f = deep + t;
if (f > maxDeep)return f;
if (t == 0) {
flag = true;
return f;
}
int nextBound = 32;
for (int i = 0; i < 4; ++i) {
if (deep > 0 && reverse(step[deep - 1], direct[i]))continue;
int tx = space / 3 + dir[i][0];
int ty = space % 3 + dir[i][1];
if (tx < 0 || tx>2 || ty < 0 || ty>2)continue;
int tz = 3 * tx + ty;
a[space] = a[tz];
a[tz] = 0;
step[deep] = direct[i];
f = dfs(deep + 1, tz);
if (flag)return f;
if (f < nextBound)nextBound = f;
a[tz] = a[space];
a[space] = 0;
}
return nextBound;
}
int main() {
char x;
int space;
for (int i = 0; i < n; ++i) {
scanf(" %c", &x);
if (x == '0') {
a[i] = 0;
space = i;
}
else a[i] = x - '0';
}
maxDeep = h();
while (true) {
flag = false;
maxDeep = dfs(0, space);
if (flag) {
printf("%d\n", maxDeep);
break;
}
}
return 0;
}