A*算法 估价函数为当前每个数到最终结果的曼哈顿距离(因为是和空格交换 所以只能改变一个数的情况 故此处满足f(x)<g(x))
对于一个矩阵的表示(因为要判断vis)可以使用暴力n*n康托展开
但是我的代码跑得很慢 应该可以双向bfs什么的会快一点(或者discuss里好像有单向过的?)
代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<string>
#include<map>
using namespace std;
inline int abss(int x)
{
return x>0?x:-x;
}
struct node
{
int a[9];
string s;
int g()
{
int ret=0;
for(int i=1;i<9;++i)
{
int x=i/3+1,y=i%3+1;
int u=(a[i]-1)/3+1,v=(a[i]-1)%3+1;
ret+=abss(x-u)+abss(y-v);
}
return ret;
}
int cantor()
{
int ret=0;
int m=1;
for(int i=8;i>=0;--i)
{
int sum=0;
for(int k=0;k<i;++k)
{
if(a[k]<a[i])++sum;
}
ret+=(a[i]-sum-1)*m;
m*=(9-i);
}
return ret+1;
}
void print()
{
for(int i=0;i<9;++i)printf("%d ",a[i]);
printf("\n");
}
//useless,just to work with "pair"
bool operator>(const node b)const
{
return true;
}
bool operator<(const node b)const
{
return true;
}
}k;
priority_queue<pair<int,node> >q;
bool vis[400005];
int du[4]={0,0,1,-1};
int dv[4]={1,-1,0,0};
char lt[4]={'r','l','d','u'};
string bfs()
{
while(!q.empty())
{
node x=q.top().second;
int t=-q.top().first-x.g();
q.pop();
int k=x.cantor();
if(vis[k])continue;
vis[k]=true;
if(k==1)
{
return x.s;
}
int pl;
for(int i=0;i<9;++i)
{
if(x.a[i]==9)
{
pl=i;
break;
}
}
int u=pl/3+1,v=pl%3+1;
for(int i=0;i<4;++i)
{
node tx=x;
int tu=u+du[i],tv=v+dv[i];
int t0=tu*3-3+tv-1;
if(tu>=1&&tu<=3&&tv>=1&&tv<=3)
{
swap(tx.a[pl],tx.a[t0]);
tx.s=x.s+lt[i];
q.push(make_pair(-t-1-tx.g(),tx));
}
}
}
return "ERROR";
}
int main()
{
char c;
for(int i=0;i<9;++i)
{
cin>>c;
if(c>='0'&&c<='9')
{
k.a[i]=c-'0';
}
else k.a[i]=9;
}
int num=0;
for(int i=0;i<9;++i)
{
if(k.a[i]==9)continue;
for(int j=0;j<i;++j)
{
if(k.a[j]==9)continue;
if(k.a[j]>k.a[i])++num;
}
}
if(num&1)
{
printf("unsolvable\n");
return 0;
}
k.s="";
q.push(make_pair(0-k.g(),k));
cout<<bfs()<<endl;
return 0;
}
/*
6 4 7 8 5 x 3 2 1
*/