洛谷P1379八数码题解

这种题目显然是个\(bfs\)。(因为要求最小步数)
每次枚举0向哪移动,用\(map\)判重即可大佬都是用康托展开或者是hash,但是我不会
\(map\)是因为转成9位数之后开\(bool\)数组存不下会hash和康托展开的大佬当我在放屁
单向\(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};//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声一片.jpg

当然最后一个点是起始状态=终点状态
好了我们知道单向\(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*?双向bfs能搞定的东西用什么A*

posted @ 2020-04-11 09:37  千载煜  阅读(206)  评论(0编辑  收藏  举报