BFS与双向BFS Knight Moves(经典棋盘问题!!!)

来源:互联网 发布:coc五级龙数据 编辑:程序博客网 时间:2024/05/29 13:11

题意:棋盘上移动判断多少步可以到达(确认是可以到达的)

思路:BFS广度搜索,每一个点最多有8个可能的位置



然后依次“枚举”即可。

 该版本为队列中存贮的为int 型的数据,每一组数据要压入队列3次,相应的出队列也是三次


#include <iostream>#include <cstdio>#include <cstring>#include <queue>using namespace std;//定义方向数组dir 为8个方向的偏移量struct position{    int x,y;};position dir[8]={{-2,1},{-2,-1},{-1,-2},{1,-2},{2,-1},{2,1},{1,2},{-1,2}};char c[6];int a[6];queue<int>que;bool vis[9][9];int ans;bool in(int a,int b){    if(a>0&&a<=8&&b>0&&b<=8)        return true;    return false;}int BFS(){    int col,row;//定义列,行,计数器    ans=0;    que.push(a[0]); //起点列    que.push(a[1]); //起点 行    que.push(ans);  //起点步数    vis[a[1]][a[0]]=true;    while(!que.empty())    {        col=que.front(); que.pop();        row=que.front(); que.pop();        ans=que.front(); que.pop();//取编号        if(col==a[2]&&row==a[3]) //到达目标状态          return ans;        for(int i=0;i<8;i++) //向8个方向扩展        {            //扩展入队列          if(in(row+dir[i].x,col+dir[i].y)&&!vis[row+dir[i].x][col+dir[i].y]){            que.push(col+dir[i].y);            que.push(row+dir[i].x);            que.push(ans+1);            vis[row+dir[i].x][col+dir[i].y]=true;          }        }    }}int main(){    int i,j;    while(gets(c))    {        while(!que.empty())            que.pop();        for(i=0;i<=8;i++)            for(j=0;j<=8;j++)              vis[i][j]=false;        a[0]=c[0]-'a'+1;        a[1]=c[1]-'0';        a[2]=c[3]-'a'+1;        a[3]=c[4]-'0';        BFS();        printf("To get from %c%c to %c%c takes %d knight moves.\n",c[0],c[1],c[3],c[4],ans);    }    return 0;}

此版本是使用了结构体之后,把之前版本的一组三个数据放在结构体node中,队列类型为node ,所以一组数据入出队列以次即可

#include <iostream>#include <cstdio>#include <cstring>#include <queue>using namespace std;struct node{    int x,y,sum;};struct position{    int x,y;};position dir[8]={{-2,1},{-2,-1},{-1,-2},{1,-2},{2,-1},{2,1},{1,2},{-1,2}};char c[6];int  a[6];queue <node> que; //什么类型<>中就放入什么bool vis[10][10];int ans;bool in(int x,int y){    if(x<=8&&x>0&&y>0&&y<=8)        return true;    return false;}int BFS(){    ans=0;    node t,m;    t.x=a[0]; t.y=a[1]; t.sum=ans;    memset(vis,0,sizeof(vis));  //初始化访问数组    vis[t.x][t.y]=1;  //初始点初始化    que.push(t);    //初始点压入队列    while(!que.empty())    {        t=que.front(); que.pop();        if(t.x==a[3]&&t.y==a[4])        {            ans=t.sum;           // printf("%d",ans);            return ans;   //到达目标位置,返回        }        for(int i=0;i<8;i++)        {            if(in(t.x+dir[i].x,t.y+dir[i].y)&&!vis[t.x+dir[i].x][t.y+dir[i].y])            {                m.x=t.x+dir[i].x;                m.y=t.y+dir[i].y;                m.sum=t.sum+1;                que.push(m);            }        }    }}int main(){   while(gets(c))   {       while(!que.empty())        que.pop();       a[0]=c[0]-'a'+1;       a[1]=c[1]-'0';       a[3]=c[3]-'a'+1;       a[4]=c[4]-'0';       BFS();       printf("To get from %c%c to %c%c takes %d knight moves.\n",c[0],c[1],c[3],c[4],ans);   }   return 0;}


下面是双向BFS的数组版本,但是有bug,这里给出代码的大体思路。
#include <iostream>#include <cstdio>#include <cstring>#include <queue>using namespace std;struct position{    int x,y;};//定义方向数组dirposition dir[8]={{-2,1},{-2,-1},{-1,-2},{1,-2},{2,-1},{2,1},{1,2},{-1,2}};char c[6];int a[6];queue<int> que1,que2;int vis[9][9];int cnt,ans,ans1,ans2;int  flag;bool in (int a,int b){    if(a>0&&a<=8&&b>0&&b<=8)        return true;    return false;}//此题目中输入的行列顺序为先列后行void single_BFS1(){    int col,row,stp,i;    col=que1.front();  que1.pop();    row=que1.front();  que1.pop();    stp=que1.front();  que1.pop();    for(i=0;i<8;i++)    {        if(in(row+dir[i].x,col+dir[i].y)&&vis[row+dir[i].x][col+dir[i].y]!=1)        {            ans1=stp+1;            if(vis[row+dir[i].x][col+dir[i].y]==2)            {                flag=0;                ans=ans1+ans2;                return ;            }        }        que1.push(col+dir[i].y);        que1.push(row+dir[i].x);        que1.push(ans2);        vis[row+dir[i].x][col+dir[i].y]=1;    }}void single_BFS2(){    int col,row,stp,i;    col=que2.front();  que2.pop();    row=que2.front();  que2.pop();    stp=que2.front();  que2.pop();    for(i=0;i<8;i++)    {        if(in(row+dir[i].x,col+dir[i].y)&&vis[row+dir[i].x][col+dir[i].y]!=2)        {            ans2=stp+1;            if(vis[row+dir[i].x][col+dir[i].y]==1)            {                flag=0;                ans=ans1+ans2;                return ;            }        }        que2.push(col+dir[i].y);        que2.push(row+dir[i].x);        que2.push(ans2);        vis[row+dir[i].x][col+dir[i].y]=2;    }}int main(){    while(gets(c))    {        while(!que1.empty())  que1.pop();        while(!que2.empty())  que2.pop();        for(int i=0;i<=8;i++)            for(int j=0;j<=8;j++)             vis[i][j]=0;        a[0]=c[0]-'a'+1;        a[1]=c[1]-'0';        a[2]=c[3]-'a'+1;        a[3]=c[4]-'0';        flag=1; ans=ans1=ans2=0;        int step=0;        que1.push(a[0]);//起点入队列        que1.push(a[1]);        que1.push(step);        vis[a[1]][a[0]]=1;        que2.push(a[2]);//终点入队列        que2.push(a[3]);        que2.push(step);        vis[a[3]][a[2]]=2;        if(a[0]==a[2]&&a[1]==a[3]){           printf("To get from %c%c to %c%c takes 0 knight moves.\n",c[0],c[1],c[3],c[4]);        }         else{           while(flag)            {                cnt=que1.size()/3;  //统计本层节点个数,正向BFS                while(cnt--&&flag)  //本层节点为扩展完,且未相遇标志flag为true                    single_BFS1();  //正向BFS                cnt=que2.size()/3;//统计本层节点个数,正向BFS                while(cnt--&&flag)//本层节点为扩展完,且未相遇标志flag为true                    single_BFS2();//反向BFS            }            printf("%d %d %d\n",ans,ans1,ans2);            //printf("To get from %c%c to %c%c takes %d knight moves.\n",c[0],c[1],c[3],c[4],ans);         }    }    return 0;}

此为结构体型的双向BFS,值得学习的不仅仅是双向BFS的思路,还有将起始BFS与末尾BFS写在一起的思路。

这是这份代码最值得学习的,起始末尾BFS通用的地方通过函数传递过去,如果需要改变数值的话,加上引用即可

#include <cstdio>#include <queue>#include <algorithm>#include <cstring>using namespace std;struct position{    int x,y;};struct node{    int x,y,sum;};queue <node> que1,que2;position dir[8]={{2,1},{2,-1},{-2,1},{-2,-1},{1,-2},{1,2},{-1,-2},{-1,2}};int vis[10][10];  //1代表的是起始点的BFS 2代表的是结束点的BFSint flag,ans,ans1,ans2;char c[6];int  a[6];bool in(int a,int b){    if(a>0&&a<=8&&b>0&&b<=8)        return true;    return false;}void DBFS(queue<node>&que,int m,int n,int &res1,int res2){//m为起始 末位BFS vis所对应的 ,n则和m相对 //res为起始 末尾BFS所对应的ans    node now,next;    int x,y,stp;    now=que.front();  que.pop();    x=now.x,y=now.y;    stp=now.sum;    for(int i=0;i<8;i++) //从8个方向扩展    {        int row=now.x+dir[i].x,col=now.y+dir[i].y;        if(in(row,col)&&vis[row][col]!=m)        {            res1=stp+1;            if(vis[row][col]==n) //判断是否“相遇”            {                ans=res1+res2;                flag=0;                return ;            }            next.x=row,next.y=col;            next.sum=res1;            que.push(next);  //将next压入队列            vis[row][col]=m; //进行标记        }    }}int main(){    while(gets(c))    {        while(!que1.empty())            que1.pop();        while(!que2.empty())            que2.pop();        memset(vis,0,sizeof(vis));        a[0]=c[0]-'a'+1;        a[1]=c[1]-'0';        a[2]=c[3]-'a'+1;        a[3]=c[4]-'0';        flag=1;        ans=ans1=ans2=0;        node s,e; //起始点与结束点        s.x=a[1],s.y=a[0];        s.sum=0;        que1.push(s);        vis[s.x][s.y]=1;        e.x=a[3],e.y=a[2];        e.sum=0;        que2.push(e);        vis[e.x][e.y]=2;        //数据的初始化完成        if(a[1]==a[3]&&a[0]==a[2])             printf("To get from %c%c to %c%c takes 0 knight moves.\n",c[0],c[1],c[3],c[4]);        else        {            while(flag)            {               int num1=que1.size();  //统计本层的节点个数                while(num1--&&flag) //本层节点为扩展完且标识符flag为1                    DBFS(que1,1,2,ans1,ans2);               int num2=que2.size();  //统计本层的节点个数                while(num2--&&flag)  //本层节点为扩展完且标识符flag为1                    DBFS(que2,2,1,ans2,ans1);            }            printf("To get from %c%c to %c%c takes %d knight moves.\n",c[0],c[1],c[3],c[4],ans);        }    }}


双向BFS:起始BFS一层,末尾BFS一层,在循环当中判断是否相遇,直到flag为0.
此为效率最高的算法,当面对数据范围较大的题目时,优势将明显体现出来



原创粉丝点击