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

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

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


BFS与双向BFS Knight Moves(经典棋盘问题!!!)_第1张图片
然后依次“枚举”即可。

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


#include 
#include 
#include 
#include 
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];
queueque;
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 
#include 
#include 
#include 
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  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 
#include 
#include 
#include 
using namespace std;
struct position
{
    int x,y;
};
//定义方向数组dir
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 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 
#include 
#include 
#include 
using namespace std;
struct position
{
    int x,y;
};
struct node
{
    int x,y,sum;
};
queue  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代表的是结束点的BFS
int 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&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.
此为效率最高的算法,当面对数据范围较大的题目时,优势将明显体现出来



你可能感兴趣的:(ACM_搜索)