题目
题解思路
看前须知
在搜索中常用的 一维表示二维 行数为 k / i 列数为 k % i
A*一般用在一定到达的情况。(否则复杂度比普通bfs还高,因为使用优先队列)
所以 我们先特判掉 无法到达的情况 。 改变X的位置 逆序数对要么不变要么加2减2 。 所以当题目的逆序对数为奇数时直接特判了。
A*(边权非负)
在普通bfs的基础上引入了一个启发函数,用每个状态的曼哈顿总数来表示预计距离 , 普通的加入层数则是实际距离 。 再将启发函数值 ( 预计距离 + 实际距离 )作为优先队列的判断条件 , 从而让答案更容易找出 。
就相当于让bfs尽可能的往正确的方向走,不让他在错误的方向走太久。
实现上也有点类似dij,并且除了终点之外的点 第一次出队 不一定是最小值(多次更新) 。即被启发函数从错误的方向带回来了。
而终点一定是最小值,因为启发函数就是面向终点的情况写的。
代码实现上
先判断逆序数,再用一个哈希的last存入变成这个状态之前的状态以及操作编号(逆向输出反转即是答案,老套路了,这样省空间)
再写一个判断曼哈顿距离的函数 ,利用之前的一维化二维性质可以更方便。
优先队列为启发函数值为变量,再模拟题中的操作。
当条件更优以及没更新过就入队(别忘了加曼哈顿距离),更新last,更新dis实际距离即可。
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <map>
#include <string>
#include <unordered_map>
using namespace std;
string A , B = "123456789";
int dx[4] = {0,0,-1,1} ;
int dy[4] = {1,-1,0,0} ;
char opr[5] = "rlud" ;
int mhd ( string s )
{
int cnt = 0 ;
for (int i = 0 ; i < 9 ; i++ )
{
int tt = s[i] - '1' ;
cnt += abs( i/3 - tt/3) + abs( i% 3 - tt%3 );
}
return cnt ;
}
struct node
{
string x ;
int w ;
bool operator < (const node &other) const
{
return w > other.w;
}
};
void bfs()
{
unordered_map <string , int > dis ;
unordered_map < string , pair<char , string > > last ;
priority_queue <node> q ;
dis[A] = 0 ;
q.push({A,mhd(A)}) ;
while ( ! q.empty() )
{
node tmp = q.top();
q.pop();
if ( tmp.x == B )
break;
int pot ;
for (int i = 0 ; i < 9 ; i++ )
{
if ( tmp.x[i] == '9' )
{
pot = i ;
break ;
}
}
for (int i = 0 ; i < 4 ; i++ )
{
int fx = pot/3 + dx[i] ;
int fy = pot%3 + dy[i] ;
if ( fx >= 0 && fy >= 0 && fx < 3 && fy < 3 )
{
string pk = tmp.x ;
swap(pk[pot],pk[fx*3+fy]) ;
if ( ! dis.count(pk) || dis[pk] > dis[tmp.x] + 1 )
{
dis[pk] = dis[tmp.x] + 1 ;
last[pk].first = opr[i] ;
last[pk].second = tmp.x ;
q.push({pk,mhd(pk) + dis[pk]}) ;
}
}
}
}
string tp = B ;
string ans = "";
while ( tp != A )
{
ans += last[tp].first ;
tp = last[tp].second ;
}
reverse(ans.begin(),ans.end()) ;
cout << ans << "\n" ;
}
int main ()
{
ios::sync_with_stdio(false);
for ( int i = 0 ; i < 9 ; i++ )
{
char ch[2] ;
cin >> ch ;
if (ch[0] == 'x' )
A += '9' ;
else
A += ch[0] ;
}
int cnt = 0 ;
for (int i = 0 ; i < 9 ; i++ )
for (int j = 0 ; j < i ; j++ )
if ( A[i] != '9' && A[j] != '9' && A[j] > A[i] )
{
cnt ++ ;
}
if ( cnt % 2 )
cout << "unsolvable\n" ;
else
bfs();
return 0 ;
}