P1379 八数码难题
题解1:朴素广搜
注意细节
code1
#include<bits/stdc++.h>
using namespace std;
int poi[4]={-3,1,-1,3};
int main()
{
string s;
cin>>s;
queue<string> q;
map<string,int> rec;
q.push(s);
rec[s]=1;
while(q.size())
{
string now=q.front();
q.pop();
if(now=="123804765")break;
for(int i=0;i<9;i++)
if(now[i]=='0')
{
for(int j=0;j<4;j++)
{
int id=i+poi[j];
if(id<0||id>8||id==2&&i==3||id==3&&i==2||id==5&&i==6||id==6&&i==5)continue;//注意细节,如果位于矩阵边缘就不能进行某些操作!!
string next=now;
swap(next[i],next[id]);
if((rec[next]>rec[now]+1||!rec[next])&&(rec[next]=rec[now]+1)) q.push(next);
}
break;
}
}
cout<<rec["123804765"]-1;
return 0;
}
题解2
A*搜索,其实在我看来像是一种贪心,通过预估函数预估走这个节点到达终点需要的花费和已经花费的,然后按花费从小到大排序,优先遍历小的
由于本题数据较小,所以这里优先遍历能通过的,再因为本题数据较小,所以预估能到达的都遍历
又因为迭代深度达到一定时就一定可以到达,所以二分深度,然后贪心深搜(因为深度一定,快速达到深度,比广搜更高效)
code2
#include<bits/stdc++.h>
using namespace std;
int xx[4]={1,0,-1,0},yy[4]={0,1,0,-1};
string raw="123804765";
string s;
int dif()
{
int ans=0;
for(int i=0;i<9;i++)
{
if(s[i]=='0') continue;
int pos=raw.find(s[i]);
int x=i/3,y=i%3;
int x1=pos/3,y1=pos%3;
ans+=abs(x-x1)+abs(y-y1);
}
return ans;
}
int depth;
int ss(int sum,int fa)
{
int dif1=dif();
if(dif1==0)return 1;
if(sum+dif1>depth)return 0;
int pos=s.find('0');
int x=pos/3,y=pos%3;;
for(int i=0;i<4;i++)
{
int x1=x+xx[i],y1=y+yy[i];
if(x1>2||x1<0||y1>2||y1<0) continue;
int pos1=x1*3+y1;
if(pos1==fa) continue;
swap(s[pos],s[pos1]);
int re=ss(sum+1,pos);
swap(s[pos],s[pos1]);
if(re)return 1;
}
return 0;
}
int main()
{
cin>>s;
int l=-1,r=27;
while(l<r-1)
{
depth=(l+r)/2;
if(ss(0,-1)) r=depth;
else l=depth;
}
cout<<r;
return 0;
}

浙公网安备 33010602011771号