一.题目链接:
HDU-1043
二.题目大意:
八数码经典问题.
不懂的去玩 4399
三.分析:
挂上几个大佬的链接:
八数码解的存在性证明
康拓展开
直接 BFS TLE 了.
这里 反向 BFS 很妙,只搜索一次,把所有状态都记录下来.
四.代码实现:
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-6
#define pi acos(-1.0)
#define ll long long int
using namespace std;
const int M = (int)5e5;
struct node
{
int D[9];
int x;
int y;
};
struct node start;
int son[M + 5];
bool vis[M + 5];
char dir[M + 5];
int Move[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
int Reverse_Num()
{
int cnt = 0;
for(int i = 0; i < 9; ++i)
{
for(int j = 0; j < i; ++j)
{
if(start.D[i] && start.D[j] && start.D[j] > start.D[i])
cnt++;
}
}
return cnt;
}
int cantor(struct node p)
{
int sum = 0;
int fac = 40320;
for(int i = 0; i < 9; ++i)
{
int cnt = 0;
for(int j = i + 1; j < 9; ++j)
{
if(p.D[j] < p.D[i])
cnt++;
}
sum += fac * cnt;
if(i == 8)
return sum;
fac /= 8 - i;
}
}
void bfs()
{
struct node p, t;
for(int i = 0; i < 8; ++i)
p.D[i] = i + 1;
p.D[8] = 0;
p.x = p.y = 2;
queue <node> q;
q.push(p);
int can1, can2;
can1 = cantor(p);
vis[can1] = 1;
while(!q.empty())
{
p = q.front();
q.pop();
can1 = cantor(p);
for(int i = 0; i < 4; ++i)
{
t = p;
t.x += Move[i][0];
t.y += Move[i][1];
if(t.x < 0 || t.x >= 3 || t.y < 0 || t.y >= 3)
continue;
int pos = t.x * 3 + t.y;/// r l d u
if(i == 0)
{
swap(t.D[pos], t.D[pos - 1]);
can2 = cantor(t);
if(!vis[can2])
{
vis[can2] = 1;
dir[can2] = 'l';
son[can2] = can1;
q.push(t);
}
}
else if(i == 1)
{
swap(t.D[pos], t.D[pos + 1]);
can2 = cantor(t);
if(!vis[can2])
{
vis[can2] = 1;
dir[can2] = 'r';
son[can2] = can1;
q.push(t);
}
}
else if(i == 2)
{
swap(t.D[pos], t.D[pos - 3]);
can2 = cantor(t);
if(!vis[can2])
{
vis[can2] = 1;
dir[can2] = 'u';
son[can2] = can1;
q.push(t);
}
}
else if(i == 3)
{
swap(t.D[pos], t.D[pos + 3]);
can2 = cantor(t);
if(!vis[can2])
{
vis[can2] = 1;
dir[can2] = 'd';
son[can2] = can1;
q.push(t);
}
}
}
}
}
int main()
{
bfs();
char ch;
while((ch = getchar()) > 0)
{
int pos = 0;
while(ch != '\n')
{
if(ch >= '0' && ch <= '8')
start.D[pos++] = ch - '0';
else if(ch == 'x')
start.D[pos++] = 0;
ch = getchar();
}
if(Reverse_Num() & 1)
{
printf("unsolvable\n");
continue;
}
int can = cantor(start);
while(can != 46233)
{
printf("%c", dir[can]);
can = son[can];
}
printf("\n");
}
return 0;
}