この種の問題は明らかに\(bfs \)です。(最小ステップ数が必要なため)
0が移動する場所を列挙するたびに、\(マップ\)を使用して重量を判断できます。大物はCantorを使用して展開またはハッシュしますが、\(マップ\)を
使用しないので、 9桁に変換した後、\(bool \)配列は保存されません。一方向の\(bfs \)を実行しているときに、ハッシュとCantoを展開する大物:
int X[9]={1,1,1,2,2,2,3,3,3},Y[9]={1,2,3,1,2,3,1,2,3};//数转矩阵用的
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};//0的移动方向
int hy[4][4]=//矩阵的位置对应的数的位置
{{0,0,0,0},
{0,0,1,2},
{0,3,4,5},
{0,6,7,8}
};
string k;
struct qwq{
string u;//这里的9位数我用字符串存的
int bs,lig;//bs记录步数,lig记录0的位置
};
queue<qwq> q;
map<int,bool> usd;
int main()
{
cin>>k;int lig;
for(int i=0;i<9;i++)
if(k[i]=='0') {lig=i;break;}
qwq a;
a.u=k;a.bs=0;a.lig=lig;
q.push(a);
while(!q.empty())
{
qwq b=q.front();
q.pop();
string mbl=b.u;int qmf=0;
for(int i=0;i<9;i++)
qmf=qmf*10+mbl[i]-48;
if(qmf==123804765) {//是否到达最终状态
printf("%d",b.bs);break;
}
int lg=b.lig;
for(int i=0;i<4;i++)
{
int xx=X[lg]+dx[i],yy=Y[lg]+dy[i];
if(xx<1||xx>3||yy<1||yy>3) continue;
qwq nw;
nw=b;
int e=b.lig,f=hy[xx][yy];
nw.lig=f;nw.u[e]=b.u[f];nw.u[f]=b.u[e];//这一坨是交换0和目标位置的数(手写swap)
nw.bs=b.bs+1;
int pd=0;string pp=nw.u;//计算当前的数
for(int i=0;i<9;i++)
pd=pd*10+pp[i]-48;
if(!usd[pd]) q.push(nw);
}
}
}
それを回して
Tの音を聞いてください。
もちろん、最後のポイントは開始状態=終了状態です。
まあ、ここでは単方向\(bfs \)は有望ではない
ので、双方向\(bfs \)
双方向\(bfs \):
int X[9]={1,1,1,2,2,2,3,3,3},Y[9]={1,2,3,1,2,3,1,2,3};//数转矩阵用的
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
int hy[4][4]=//矩阵的位置对应的数的位置
{{0,0,0,0},
{0,0,1,2},
{0,3,4,5},
{0,6,7,8}
};
string k;
queue<qwq> q1,q2;
map<int,int> usd,bu1,bu2;//usd记录被哪一边访问过,bu1记录q1中状态的步数,bu2记录q2中状态的步数(感觉bu1和bu2可以和起来的样子)
void bfs()
{
while(1)
{
bool bj=0;
if(q1.size()>q2.size())//哪边少先扩展哪边
{
qwq nw=q2.front();
q2.pop();
int lg=nw.lig;
for(int i=0;i<4;i++)
{
int xx=X[lg]+dx[i],yy=Y[lg]+dy[i];//枚举0的转移位置
if(xx<1||xx>3||yy<1||yy>3) continue;
string s1=nw.u;int pd=0;
swap(s1[lg],s1[hy[xx][yy]]);//懒得手写swap了
for(int i=0;i<9;i++)
pd=pd*10+s1[i]-48;
if(usd[pd]==1) {printf("%d",nw.bs+1+bu1[pd]);bj=1;break;}//如果两边搜的点能接上,则找到最短步数
if(!usd[pd]) //如果该状态还未被访问过
{
qwq nxt;nxt.u=s1;nxt.lig=hy[xx][yy];
usd[pd]=2;nxt.bs=nw.bs+1;bu2[pd]=nxt.bs;q2.push(nxt);
}
}
}
else
{
qwq nw=q1.front();
q1.pop();
int lg=nw.lig;
for(int i=0;i<4;i++)
{
int xx=X[lg]+dx[i],yy=Y[lg]+dy[i];
if(xx<1||xx>3||yy<1||yy>3) continue;
string s1=nw.u;int pd=0;
swap(s1[lg],s1[hy[xx][yy]]);
for(int i=0;i<9;i++)
pd=pd*10+s1[i]-48;
if(usd[pd]==2) {printf("%d",nw.bs+1+bu2[pd]);bj=1;break;}
if(!usd[pd])
{
qwq nxt;nxt.u=s1;nxt.lig=hy[xx][yy];
usd[pd]=1;nxt.bs=nw.bs+1;bu1[pd]=nxt.bs;q1.push(nxt);
}
}
}
if(bj) break;//找到答案就跳出
}
}
もちろん、特別な状況に、注意を払う文初期状態=状態の終了
後、\(AC \) 、かつ迅速に走った
何を?A *とはどういう意味ですか?A *は双方向bfsに何を使用できますか