版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39562952/article/details/82881943
思路:跟hdu 1043 其实差不多,只是最后的状态变成了非唯一情况;我们要做的就是把最后的状态变成唯一的或者唯几的情况;
看了网上大佬的思路之后发现,不管最后的状态怎么变化,都可以映射成9种,也就是X放在其中的9个位置,然后按照映射关系把起始状态也映射一下,最后两个映射的达到路径跟要求的路径其实是一样的(虽然不知道为什么,但是事实如此);
因为有9种情况,那么就有9张表分别代表到达9个末位置的路径;
怎么保证是字典序最小的话,只要搜素方向是:dlru就行了;
代码如下:
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <cstring>
#include <climits>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stdio.h>
#include <sstream>
#include <map>
#define esp 1e-4
using namespace std;
/*8数码进阶问题,把终点映射成9种情况,分别对应x的9个位置,然后打出9种位置的表
(即各种点到终点的路径)
*/
char inti[9][10] =
{
"912345678",
"192345678",
"129345678",
"123945678",
"123495678",
"123459678",
"123456978",
"123456798",
"123456789",
};
int fac[] = { 1,1,2,6,24,120,720,5040,40320 };//0-8的阶乘
int then[4][2] = { {1,0},{0,-1},{0,1},{-1,0} };//代表向下,向左,向右,向上 ,因为要字典序最小,所有dlru
struct node1//路径点
{
int f;//
char way;//代表到达这个点的走法
};
node1 path[9][400000];//9种情况
struct node2//bfs中queue中的点
{
char a[10];
int ktval;
int n;//x在该状态下的位置
};
int kt(char *a)//计算康托展开的值
{
int ans = 0;
for (int i = 0; i < 9; i++)
{
int k = 0;
for (int j = i + 1; j < 9; j++)
{
if (a[i] > a[j])
k++;
}
ans += k * fac[8 - i];
}
return ans;
}
void bfs(char a[10], int pos)
{
int ktval = kt(a);
queue<node2> q;
node2 temp;
strcpy(temp.a, a);
temp.ktval = ktval;
temp.n = pos;
q.push(temp);
path[pos][ktval].f = 0;
while (!q.empty())
{
for (int i = 0; i < 4; i++)
{
int nx = q.front().n / 3 + then[i][0];//行
int ny = q.front().n % 3 + then[i][1];//列
int nn = nx * 3 + ny;//下个位置
if (nx < 0 || nx >= 3 || ny < 0 || ny >= 3)
continue;
temp = q.front();
swap(temp.a[nn], temp.a[q.front().n]);
ktval = kt(temp.a);
if (path[pos][ktval].f == -1)//没访问过
{
temp.ktval = ktval;
temp.n = nn;
q.push(temp);
path[pos][ktval].f = q.front().ktval;
if (i == 0) path[pos][ktval].way = 'd';
if (i == 1) path[pos][ktval].way = 'l';
if (i == 2) path[pos][ktval].way = 'r';
if (i == 3) path[pos][ktval].way = 'u';
}
}
q.pop();
}
}
int main()
{
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 400000; j++)
{
path[i][j].f = -1;//代表没访问过
}
}
for (int i = 0; i < 9; i++)
{
bfs(inti[i], i);
}
int T;
cin >> T;
char s1[10];
char s2[10];
int pos;//代表要达到的状态种x的位置
for (int ca = 1; ca <= T; ca++)
{
cin >> s2 >> s1;
printf("Case %d:", ca);
for (int i = 0; i < 9; i++)
{
if (s1[i] == 'X')
{
s1[i] = '9';
}
if (s2[i] == 'X')
{
s2[i] = '9';
pos = i;
}
}
int a[10];//代表映射关系:i--a[i]
int x = 1;
for (int i = 0; i < 9; i++)
{
if (s2[i] == '9')
continue;
a[s2[i] - '0'] = x;
x++;
}
for (int i = 0; i < 9; i++)
{
if (s1[i] == '9')
continue;
s1[i] = a[s1[i] - '0'] + '0';
}
//cout << s1 << endl;
int ktval = kt(s1);
int endktval = kt(inti[pos]);
int ans = 0;
char ansc[10000];
if(path[pos][ktval].f==-1)
{
cout <<" 0" << endl;
continue;
}
while (ktval != endktval)
{
ansc[ans++] = path[pos][ktval].way;
ktval = path[pos][ktval].f;
}
cout <<" "<< ans << endl;
for(int i=ans-1;i>=0;i--)
cout << ansc[i];
cout<<endl;
}
return 0;
/*
22222
564178X23
7568X4123
87654321X 321X45678
*/
}