2015年百度之星程序设计大赛 - 资格赛 1005 下棋

下棋

 
 Accepts: 345
 
 Submissions: 2382
 Time Limit: 6000/3000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
Problem Description

NM 的棋盘上有一个受伤的国王与一个要去救援国王的骑士,他们每个单位时间必须同时移动一次寻找对方。如下图所示,黑色的图例表示国王(右)或骑士(左)当前所在的位置,那么灰色的位置表示在一次移动中他们可能到达的位置。国王伤势严重,因此他必须在K个单位时间内得到骑士的救援,否则会挂掉。问国王是否可以在K个单位时间内获得救援,如果可以,最短需要花多少个单位时间。

Input

第一行包含一个整数 T,1T50 代表测试数据的组数,接下来 T 组测试数据。

每组测试数据第一行包含三个整数 N,M,K , 且 2N,M1000 1K200 。第二行两个整数 Xking,Yking ,对应国王所在方格的坐标。第三行两个整数 Xknight,Yknight ,对应骑士所在方格的坐标。其中 1Xking,XknightN,1Yking,YknightM ,保证骑士与国王一开始不在同一个方格内且他们都可以移动。:

Output

对于每组测试数据,输出两行:

第一行输出:"Case #i:"。 i 代表第 i 组测试数据。

第二行输出测试数据的结果,如果国王可以得到救援,则输出最快需要花多少个单位时间。否则,输出“OH,NO!”。

Sample Input
2
3 2 1
1 1
3 1
3 3 1
1 1
1 2 
Sample Output
Case #1:
1
Case #2:
OH,NO!


分析:
广搜,先记录骑士每步到达的地方,看国王走相同的步数能否到达。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
#define cle(a, i) memset(a, i, sizeof(a))
#define uf(i, a, b) for(int i = a; i <= b; i++)
using namespace std;

struct node
{
    node(int X, int Y, int C) {
        x = X;
        y = Y;
        cnt = C;
    }
    int x, y, cnt;
} ;
const int maxn = 1000 + 10;
int N, M, K, wx, wy, qx, qy;
int Qv[maxn][maxn], Wv[maxn][maxn], Ev[maxn][maxn];
const int Qd[8][2] = { 2, 1, 1, 2, 2, -1, 1, -2, -1, -2, -2, -1, -1, 2, -2, 1 };
const int Wd[8][2] = { 1, 1, 1, -1, 1, 0, -1, -1, -1, 1, -1, 0, 0, 1, 0, -1 };
queue<node> Q, W;

int Qcheck(int x, int y)
{
    return x >= 1 && x <= N && y >= 1 && y <= M && !Qv[x][y];
}

int Wcheck(int x, int y)
{
    return x >= 1 && x <= N && y >= 1 && y <= M && !Wv[x][y];
}

int bfs()
{
    while(!Q.empty()) Q.pop();
    while(!W.empty()) W.pop();
    node next(node(0, 0, 0));
    node now(node(0, 0, 0));
    W.push(node(wx, wy, 0));
    Q.push(node(qx, qy, 0));
    for (int c = 0; c < K; c++) {
        cle(Ev, 0);             //每步骑士到达的地方
        while (Q.front().cnt == c) {    //将当前步数为c的都取出,拓展下一步
            now = Q.front();
            Q.pop();
            uf(i, 0, 7) {       //八个方向
                int tx = now.x + Qd[i][0];
                int ty = now.y + Qd[i][1];
                if (Qcheck(tx, ty)) {
                    Qv[tx][ty] = 1;
                    Ev[tx][ty] = 1;
                    next.cnt = now.cnt + 1;
                    next.x = tx;
                    next.y = ty;
                    Q.push(next);
                }
            }
        }
        while (W.front().cnt == c) {
            now = W.front();
            W.pop();
            uf(i, 0, 7) {
                int tx = now.x + Wd[i][0];
                int ty = now.y + Wd[i][1];
                if (Wcheck(tx, ty)) {
                    if (Ev[tx][ty]) return c + 1;   //若国王在相同的步数也到达,success
                    Wv[tx][ty] = 1;
                    next.cnt = now.cnt + 1;
                    next.x = tx;
                    next.y = ty;
                    W.push(next);
                }
            }
        }
    }
    return -1;
}
int main()
{
    int t, cas = 1;
    scanf("%d", &t);
    while (t--)
    {
        cle(Wv, 0);
        cle(Qv, 0);
        scanf("%d%d%d", &N, &M, &K);
        scanf("%d%d%d%d", &wx, &wy, &qx, &qy);
        int k = bfs();
        printf("Case #%d:\n", cas++);
        if (k == -1) printf("OH,NO!\n");
        else printf("%d\n", k);
    }
    return 0;
}
 
  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值