题意:已经很明显了。
思路:
1. bfs+map标记
纯bfs暴力算法,没有太大意义。只能过60%的数据(比赛也只能得这60分)。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
string be,ed;
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
int ans;
map<string,int> mp;
struct Point
{
int x,y,ans;
string check;
Point(int sx,int sy,int an,string ch):x(sx),y(sy),ans(an),check(ch){}
};
void bfs(int s)
{
int sx=s%3+1,sy=s%3+1;
queue<Point> que;
Point *tt = new Point(sx,sy,0,be);
mp[be]=1;
que.push(*tt);
while(que.empty()==0)
{
Point tmp = que.front();
que.pop();
for(int i=0;i<4;i++)
{
int nx=tmp.x+dx[i],ny=tmp.y+dy[i];
if(nx>3||ny>3||nx<1||ny<1) continue;
int lo = (nx-1)*3+ny-1;
int old=(tmp.x-1)*3+tmp.y-1;
//cout<<lo<<" "<<old<<endl;
string tmp2 =tmp.check;
swap(tmp2[lo],tmp2[old]);
// cout<<tmp2<<endl;
//if(se.find(tmp2)!=se.end()) continue;
if(mp[tmp2]==1) continue;
Point *tt=new Point(nx,ny,tmp.ans+1,tmp2);
if(tmp2==ed)
{
ans=tmp.ans+1;
return;
}
que.push(*tt);
mp[tmp2]=1;
}
}
ans=-1;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
cin>>be;
cin>>ed;
for(int i=0;i<be.size();i++)
{
if(be[i]=='.')
{
bfs(i);
break;
}
}
cout<<ans<<endl;
return 0;
}
2. A* 算法
之前没学过A*,所以去把A*给学了一下。
看了前面的两篇博客,就可以做这个题了。
这个题其实已经简化了,因为只能搜索上下左右4个方向,没有斜对角的移动。所以G值的变化都是+1.
其次,我们采用曼哈顿距离作为我们的L值,曼哈顿距离如何求?找到当前序列和结尾序列相同的字符,用它们的坐标做差,求绝对值即可。
剩下的还是边看代码边理解吧。我也是第一次做A*,不上代码讲不清。
代码:
#include <bits/stdc++.h>
using namespace std;
int HASH[9]={1,1,2,6,24,120,720,5040,40320} ;
int dest[3][3];
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
int vis[500000];
struct Point
{
int mp[3][3];
int x,y;
int hash;//hash值
int g,h,f;//A*算法的三个参数
bool operator<(const Point b) const{
return f==b.f?h>b.h:f>b.f;
}//我们采用优先队列来实现最小堆,所以需要重载<运算符
void getHash() //利用康托展开求hash值
{
int oth[9],k=0;
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
oth[k++]=mp[i][j];//将矩阵转化为数组
}
}
hash=0;
for(int i=0;i<9;i++)
{
k=0;
for(int j=i+1;j<9;j++)
{
if(oth[i]>oth[j])
{
k++;//找后面有多少个数比他小即可。
}
}
hash+=k*HASH[8-i];
}
}
void getH() //哈曼顿距离
{
h=0;
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
for(int m=0;m<3;m++)
{
for(int n=0;n<3;n++)
{
if(mp[i][j]==dest[n][m])
{
h+=abs(i-n)+abs(j-m);
}
}
}
}
}
}
bool check(){
if(x<0||y<0||x>2||y>2){
return false;
}
return true;
}
}start,endss;
int Astart()
{
priority_queue<Point> que;
que.push(start);
vis[start.hash]=1;
while(que.empty()==0)
{
Point tmp = que.top();
if(tmp.hash==endss.hash)
{
return vis[tmp.hash];
}
que.pop();
for(int i=0;i<4;i++)
{
Point next = tmp;
next.x+=dx[i];
next.y+=dy[i];
if(next.check()==0) continue;
swap(next.mp[next.x][next.y],next.mp[tmp.x][tmp.y]);
next.getHash();
if(vis[next.hash]==0) //没有访问过
{
next.getH();
next.g+=1;
next.f=next.g+next.h;
vis[next.hash]=next.g;
que.push(next);
}
else
{
if(next.g+1<vis[next.hash]) //访问过,但是g值比原来更小,则考虑再次访问
{
next.g+=1;
vis[next.hash]=next.g;
next.getH();
next.f=next.g+next.h;
que.push(next);
}
}
}
}
return -1;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
string s,e;
cin>>s;
cin>>e;
for(int i=0;i<9;i++)//预处理
{
if(s[i]!='.') start.mp[i/3][i%3]=s[i]-'0';
else{
start.mp[i/3][i%3]=0;
start.x=i/3;
start.y=i%3;
}
}
for(int i=0;i<9;i++)
{
if(e[i]!='.') endss.mp[i/3][i%3]=e[i]-'0';
else endss.mp[i/3][i%3]=0;
dest[i/3][i%3]=endss.mp[i/3][i%3];
}
memset(vis,0,sizeof(vis));
endss.getHash();
endss.getH();
endss.g=-1;
endss.f=endss.h+endss.g;
start.getH();
start.getHash();
start.g=0;
start.f=start.h+start.g;
int ans=Astart();
cout<<ans<<endl;
return 0;
}