0
点赞
收藏
分享

微信扫一扫

Wiki下象棋

萍儿的小确幸 2022-03-30 阅读 84

链接:https://ac.nowcoder.com/acm/contest/30532/E

题目描述

Wiki的业余爱好就是下象棋,他不仅会下中国象棋,还会下国际象棋。他发现中国象棋和国际象棋虽然都有"马"这个棋子,但走的规则却不太一样。
国际象棋的"马"可以走"日"字,也就是说每一步只可以水平或垂直移动一点,再按对角线方面向左或者右移动(另一种解释,可以先在水平/竖直方向走两格,然后在竖直/水平方向走一格)。另外,马不允许跳出界外,也即必须跳完一步之后仍在棋盘上。如图所示:
img

中国象棋的"马"的走法也是走日字,在没有障碍物的情况下,其走法与国际象棋一样。唯一不同的是,如果马走了一格就遇到障碍物,马就不能继续向这个方向前进了(又称为"马脚")。如图所示,左上角的马因为没有障碍物,可以走八个方向,而右下角的马由于正上方有一个其他棋子,因此就不能往上方的两个方向跳了。
img

Wiki想比较一下两种马的差异,他找来了一个n行m列的大棋盘,行和列都从1开始编号。这个棋盘上已经有若干个其他棋子,马在行进的过程中不能走到这些有棋子的格子上。为了方便比较起见,假定所有棋子都在格子内部(本来中国象棋的子是放在交线上的)。Wiki先在a行b列放上国际象棋的马,算了一下它到c行d列最快要几步;又在同样的a行b列放上中国象棋的马,算了一下它到c行d列最快要几步。显然,这么手工计算很容易出错,因此Wiki想请你帮忙用程序算一下。

输入描述:

本题包含多组输入。
第一行输入一个正整数T,表示有T组输入。
每组数据的第一行包含7个数n,m,k,a,b,c,d,分别表示棋盘的行数,棋盘的列数,其他棋子的个数,起点坐标(a,b)和终点坐标(c,d)。
第二行有2k个数,每两个数代表一个其他棋子所在的坐标。数据保证不会有多个其他棋子在一个格子中,也保证(a,b)和(c,d)不会有其他棋子。

输出描述:

对于每组输入,输出一行两个数,分别是国际象棋的马和中国象棋的马从起点坐标到终点坐标最少需要走几步。若不可能到达,则输出-1。

输入示例

2
10 10 1 5 5 5 5
1 1
2 3 1 1 1 2 3
1 2

输出示例

0 0
1 -1

说明

img

AC

重新学了一遍bfs,救命,隔一段时间不用就屁也不记得了,救命

俺是笨比,因为全局变量的问题WA了一次,因为另一个自己想糊涂的点WA了两次

感觉像是裸的bfs,bfs过程中记录一下步数就行(下面这个是偷的图,嘿嘿)。
image-20220330220021828

我搞糊涂的点:

  • 国际象棋的”马“——不考虑障碍点,只考虑:该位置是否走过;该位置是否有其他棋子(不能走)
  • 中国象棋的”马“——考虑障碍点,如果是障碍点则不考虑该方向的两个的两种可能;如果不是障碍点,还要考虑:该位置是否走过;该位置是否有其他棋子(不能走)

喵的,怎么这么一写也很清晰啊,我敲代码的时候怎么老想不明白(还是碎碎念)

#include <bits/stdc++.h>
using namespace std;
const int N = 350;

int t,n,m,k,a,b,c,d;
int vis[N][N];//其他棋子位置(障碍点)
int step[N][N];//记录从起点跳到[i][j]需要多少步数
//也可以表示该点是否被访问过,没有被访问过值 < 0 (-1) 
int dx[8] = {-2,-2,-1,-1,2,2,1,1};
int dy[8] = {-1,1,-2,2,-1,1,-2,2};
int bx[8] = {-1,-1,0,0,1,1,0,0};
int by[8] = {0,0,-1,1,0,0,-1,1};
int ans1 = -1,ans2 = -1;

void bfs1(){
    queue<pair<int,int>> q;
    q.push(make_pair(a,b));//将起点压入队列
    step[a][b] = 0;//从起点到a,b的步数为0(标记为已访问)
    while(!q.empty()){
        int x = q.front().first,y = q.front().second;
        q.pop();//队首出队
        //走到终点退出
        if(x == c && y == d){
            ans1 = step[c][d];
            return;
        }
        //向八个方向扩展
        for(int i=0;i<8;i++){
            int nx = x + dx[i],ny = y + dy[i];
            //判断是否越界:nx > 0 && nx <= n && ny > 0 && ny <= m
            //判断是否访问:step[nx][ny] < 0
            //判断是否其他棋子点:!vis[nx][ny]
            if(nx > 0 && nx <= n && ny > 0 && ny <= m && step[nx][ny] < 0 && !vis[nx][ny]){
                    step[nx][ny] = step[x][y] + 1;//可以走,步数++
                    q.push(make_pair(nx,ny));
            }
        }
    }
}

void bfs2(){
    queue<pair<int,int>> q;
    q.push(make_pair(a,b));
    step[a][b] = 0;//从起点到a,b的步数为0
    while(!q.empty()){
        int x = q.front().first,y = q.front().second;
        q.pop();
        if(x == c && y == d){
            ans2 = step[c][d];
            return;
        }
        for(int i=0;i<8;i++){
            int nx = x + bx[i],ny = y + by[i];
            //判断是否越界:nx > 0 && nx <= n && ny > 0 && ny <= m
            //判断是否障碍点:!vis[nx][ny]
            if(nx > 0 && nx <= n && ny > 0 && ny <= m && !vis[nx][ny]){
                int nnx = x + dx[i],nny = y + dy[i];
                //判断是否越界:nnx > 0 && nnx <= n && nny > 0 && nny <= m
                //判断是否访问:step[nx][ny] < 0
                //判断是否其他棋子点:!vis[nnx][nny]
                if(nnx > 0 && nnx <= n && nny > 0 && nny <= m && !vis[nnx][nny] && step[nnx][nny] < 0){
                    step[nnx][nny] = step[x][y] + 1;
                    //cout << nnx << "  " << nny << endl;
                    q.push(make_pair(nnx,nny));
                }
            }
        }
    }
}

int main(){
    cin >> t;
    while(t--){
        cin >> n >> m >> k >> a >> b >> c >> d;
        memset(vis,0,sizeof(vis));
        while(k--){
            int x,y;
            cin >> x >> y;
            vis[x][y] = 1;//标记其他棋子点(障碍点)
        }
        //一开始在全局初始化了,忘记在循环中重置初始化,卡了半天(我是笨比)
        ans1 = -1,ans2 = -1;
        memset(step,-1,sizeof(step));
        bfs1();
        cout << ans1 << " ";
        memset(step,-1,sizeof(step));
        bfs2();
        cout << ans2 << endl;
    }
    return 0;
}
举报

相关推荐

0 条评论