【NOJ1043】【算法实验三】【分支限界法】跳马


1043.跳马

时限:1000ms 内存限制:10000K  总时限:3000ms

描述

在国际象棋中,马的走法与中车象棋类似,即俗话说的“马走日”,下图所示即国际象棋中马(K)在一步能到达的格子(其中黑色的格子是能到达的位置)。

方向设置
  7   6  
8       5
    K    
1       4
  2   3  


现有一200*200大小的国际象棋棋盘,棋盘中仅有一个马,给定马的当前位置(S)和目标位置(T),求出马最少需要多少跳才能从当前位置到达目标位置。

输入

本题包含多个测例。输入数据的第一行有一个整数N(1<=N<=1000),表示测例的个数,接下来的每一行有四个以空格分隔的整数,分别表示马当前位置及目标位置的横、纵坐标C(x,y)和G(x,y)。坐标由1开始。

输出

对于每个测例,在单独的一行内输出一个整数,即马从当前位置跳到目标位置最少的跳数。


#include <iostream>
#include <queue>

using namespace std;

queue <int> q1;

int used[40001];        //该格子是否被访问过

int step[40001];        //走到每一格所用步数

int n;
int cnt;    //步数
int cx,cy,gx,gy;    //从0开始

void init();    //初始化
int bfs();      //广搜
int moveto(int m, int d);   //返回格子m去方向d跳到的的格子序号
                            //如果该格不能走,返回-1
                            //序号从0开始

int main()
{
    cin>>n;
    for(int i=0; i<n; i++)
    {
        cin>>cx>>cy>>gx>>gy;

        init();     //初始化

        cnt=bfs();     //广搜

        cout<<cnt<<endl;
    }
    return 0;
}

void init()     //初始化
{
    for(int i=0; i<40001; i++)  //初始化各数组
    {
        step[i]=used[i]=0;
    }

    while(!q1.empty())     //清空队列
    {
        q1.pop();
    }

    cnt=0;
    int x=(cx-1)*200+cy-1;    //起始格子的序号
    step[x]=0;
    used[x]=1;
    q1.push(x);

}

int bfs()      //广搜
{
    while(!q1.empty())
    {
        int top=q1.front();
        //cout<<top/200<<' '<<top%200<<endl;
        q1.pop();
        for(int i=1; i<9; i++)  //八个方向
        {
            int y=moveto(top, i);
            if(y>=0) //如果可以走
            {
                if(y==(gx-1)*200+gy-1)
                {
                    return step[top]+1;
                }
                else
                {
                    used[y]=1;
                    step[y]=step[top]+1;
                    q1.push(y);
                }
            }
        }
    }
    return -1;
}

//不可走情况:已经被访问过/出界
int moveto(int m, int d)
{
    int x=m/200;
    int y=m%200;
    int next;
    switch(d)
    {
        case 1:
        {
            if(x+1<200&&y-2>=0)  //判断出界
            {
                next=(x+1)*200+(y-2);
                if(used[next]==0)   //判断是否访问过
                {
                    return next;
                }
            }
            break;
        }
        case 2:
        {
            if(x+2<200&&y-1>=0)  //判断出界
            {
                next=(x+2)*200+(y-1);
                if(used[next]==0)
                {
                    return next;
                }
            }
            break;
        }
        case 3:
        {
            if(x+2<200&&y+1<200)  //判断出界
            {
                next=(x+2)*200+(y+1);
                if(used[next]==0)
                {
                    return next;
                }
            }
            break;
        }
        case 4:
        {
            if(x+1<200&&y+2<200)  //判断出界
            {
                next=(x+1)*200+(y+2);
                if(used[next]==0)
                {
                    return next;
                }
            }
            break;
        }
        case 5:
        {
            if(x-1>=0&&y+2<200)  //判断出界
            {
                next=(x-1)*200+(y+2);
                if(used[next]==0)
                {
                    return next;
                }
            }
            break;
        }
        case 6:
        {
            if(x-2>=0&&y+1<200)  //判断出界
            {
                next=(x-2)*200+(y+1);
                if(used[next]==0)
                {
                    return next;
                }
            }
            break;
        }
        case 7:
        {
            if(x-2>=0&&y-1>=0)  //判断出界
            {
                next=(x-2)*200+(y-1);
                if(used[next]==0)
                {
                    return next;
                }
            }
            break;
        }
        case 8:
        {
            if(x-1>=0&&y-2>=0)  //判断出界
            {
                next=(x-1)*200+(y-2);
                if(used[next]==0)
                {
                    return next;
                }
            }
            break;
        }
    }
    return -1;
}



【后记】

1.写的第一个广搜,吭哧了一上午,主要卡在:

(1)坐标从[1, 1]开始,想当然的把格子也从1开始编号,结果坐标[200, 200]变成[40000]号又变成坐标[201, 0],出了bug,然后还是用回熟悉的从[0, 0]坐标开始,从0号开始编号;

(2)初始化忘记清空队列

2.用了一个moveto函数,当可以moveto的时候返回的是将要入队的格子序号(>=0),如果判断不能moveto,返回-1

猜你喜欢

转载自blog.csdn.net/qq_41727666/article/details/82957071