跳马(广搜_队列)

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

描述:

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

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

输入:

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

输出:

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

输入样例:

2

1 1 2 1

1 5 5 1

输出样例:

3

4

#include<stdio.h>
#define n 200
char a[200][200]={0};//迷宫数组(坐标由0开始)
int open[2000],openlen=2000,head,tail;
int Berow,Becol;//起点横纵坐标
int Enrow,Encol;//终点横,纵坐标

void init();
int search();
int emptyopen();
int takeoutopen();
int canmoveto(int row,int col,int *p,int *q,int i);//i代表跳马的方向
int isaim(int row,int col);
int used(int row,int col);
void addtoopen(int row,int col);
/////////////////////////////////////////////////////////////////////////
int main()
{
    int m;
    scanf("%d",&m);//m个测例
    for(int i=0;i<m;i++)
    {
        init();
        int temp=search();//若目标节点不可达,则会返回0
        printf("%d\n",temp);
    }    
    return 0;
}
void init()//初始化工作
{
    scanf("%d%d%d%d",&Berow,&Becol,&Enrow,&Encol);//起始点坐标(从1开始的)
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            a[i][j]=0;//棋盘初始化                
    head=0; tail=1;
    open[0]=(Berow-1)*n+Becol-1;//队列初始化
}
///////////////////////////////////////////////////////////////////
int search()//寻找最短步长
{
    int row,col;
    int u,r,c,num=0;
    while(!emptyopen())
    {
        u=takeoutopen();
        row=u/n;  col=u%n;
        num=a[row][col];
        for(int i=0;i<8;i++)//八个方向跳马
        {
            if(canmoveto(row,col,&r,&c,i))
            {
                if(isaim(r,c))//到达终点                
                    return(num+1);//返回最短步长                
                else if(!used(r,c))//没到达终点且未走到过
                {
                    a[r][c]=num+1;//标记走过的点
                    addtoopen(r,c);
                }
            }
        }
    }
    return 0;//全盘搜索后,还是没有找到通路
}
int emptyopen()//判断队列是否为空
{
    if(head==tail)
        return 1;
    return 0;
}
int takeoutopen()//取对列头结点
{
    int u;
    u=open[head++];
    head=head%openlen;
    return u;
}
int canmoveto(int row,int col,int *p,int *q,int i)//i代表跳马的方向
{
    switch(i)
    {
        case 1: row+=2; col--;   break;//左下1    
        case 2: row++;  col-=2;  break;//左下2    
        case 3: row--;  col-=2;  break;//左上1
        case 4: row-=2; col--;   break;//左上2 
        case 5: row-=2; col++;   break;//右上1
        case 6: row--;  col+=2;  break;//右上2
        case 7: row++;  col+=2;  break;//右下1
        case 8: row+=2; col++;   break;//右下2    
    }
    *p=row;
    *q=col;
    if(row>=0 &&col>=0 &&row<n &&col<n &&a[row][col]==0)
        return 1;
    return 0;
}
int isaim(int row,int col)//判断是否到达终点
{
    if(row==Enrow-1 &&col==Encol-1)
        return 1;
    return 0;
}
int used(int row,int col)
{
    if(a[row][col]==0)
        return 0;
    return 1;
}
void addtoopen(int row,int col)//新结点加入队列
{
    int u=row*n+col;
    open[tail++]=u;
    tail=tail%openlen;
}
原文地址:https://www.cnblogs.com/IThaitian/p/2593374.html