• 洛谷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*

  • 相关阅读:
    前端知识总汇
    html基础
    linux密码修改实验
    [ 转 ] 为 phpstorm 自定义默认 Web 服务器
    简易 PHP 教程小记
    EXPORT Man Information for Linux use COMMAND col
    CiSCO 交换机配置 SSH 登陆
    修复已损坏的交换机IMG
    Jupyter Notebook远程服务器配置[转]
    Linux 调节分辨率
  • 原文地址:https://www.cnblogs.com/lcez56jsy/p/12677790.html
Copyright © 2020-2023  润新知