1880:【13NOIP提高组】华容道

【题目描述】

小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次。于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间。

小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的:

1.在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的;

2.有些棋子是固定的,有些棋子则是可以移动的;

3.任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。 游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。

给定一个棋盘,游戏可以玩 q 次,当然,每次棋盘上固定的格子是不会变的,但是棋盘上空白的格子的初始位置、指定的可移动的棋子的初始位置和目标位置却可能不同。第 i 次玩的时候,空白的格子在第 EXi 行第 EYi 列,指定的可移动棋子的初始位置为第 SXi 行第 SYi列,目标位置为第 TXi 行第 TYi 列。

假设小 B 每秒钟能进行一次移动棋子的操作,而其他操作的时间都可以忽略不计。请你告诉小 B 每一次游戏所需要的最少时间,或者告诉他不可能完成游戏。

【输入】

第一行有 3 个整数,每两个整数之间用一个空格隔开,依次表示 n、m 和 q;

接下来的 n 行描述一个 n*m 的棋盘,每行有 m 个整数,每两个整数之间用一个空格隔开,每个整数描述棋盘上一个格子的状态,0 表示该格子上的棋子是固定的,1 表示该格子上的棋子可以移动或者该格子是空白的。

接下来的 q 行,每行包含 6 个整数依次是 EXi、EYi、SXi、SYi、TXi、TYi,每两个整数之间用一个空格隔开,表示每次游戏空白格子的位置,指定棋子的初始位置和目标位置。

【输出】

输出有 q 行,每行包含 1 个整数,表示每次游戏所需要的最少时间,如果某次游戏无法完成目标则输出−1。

【输入样例】

3 4 2
0 1 1 1
0 1 1 0
0 1 0 0
3 2 1 2 2 2
1 2 2 2 3 2

【输出样例】

2
-1

【提示】

【输入输出样例说明】

棋盘上划叉的格子是固定的,红色格子是目标位置,圆圈表示棋子,其中绿色圆圈表示目标棋子。

1. 第一次游戏,空白格子的初始位置是(3,2)(图中空白所示),游戏的目标是将初始位置在(1,2)上的棋子(图中绿色圆圈所代表的棋子)移动到目标位置(2,  2)(图中红色的格子)上。

移动过程如下:

2. 第二次游戏,空白格子的初始位置是(1, 2)(图中空白所示),游戏的目标是将初始位置在(2,2)上的棋子(图中绿色圆圈所示)移动到目标位置(3, 2)上。

要将指定块移入目标位置,必须先将空白块移入目标位置,空白块要移动到目标位置,必然是从位置(2,2)上与当前图中目标位置上的棋子交换位置,之后能与空白块交换位置的只有当前图中目标位置上的那个棋子,因此目标棋子永远无法走到它的目标位置,游戏无法完成。

【数据范围】

对于 30%的数据,1 ≤ n, m ≤ 10,q = 1;

对于 60%的数据,1 ≤ n, m ≤ 30,q ≤ 10;

对于 100%的数据,1 ≤ n, m ≤ 30,q ≤ 500。

直接上代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;

#define re register
#define LL long long
#define rep(i, x, y) for (register int i = x; i <= y; ++i)
#define repd(i, x, y) for (register int i = x; i >= y; --i)
#define maxx(a, b) a = max(a, b)
#define minn(a, b) a = min(a, b)
#define inf 1e9
#define linf 1e17

inline int read() {
    re int w = 0, f = 1; char c = getchar();
    while (!isdigit(c)) f = c == '-' ? -1 : f, c = getchar();
    while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ 48), c = getchar();
    return w * f;
}

const int maxn = 30 + 5;

struct State {
    int x, y, d;
};

queue<State> q;

struct Edge {
    int u, v, w, pre;
};

inline int convert(int x, int y, int d) {
    return x * 120 + y * 4 + d;
}

struct Node {
    int u, d;
    bool operator < (const Node &rhs) const {
        return d > rhs.d;
    }
};

priority_queue <Node> Q;

struct Graph {
    Edge edges[maxn * maxn * maxn];
    int G[maxn * maxn * maxn], n, m;
    int d[maxn * maxn * maxn], vis[maxn * maxn * maxn];
    void init(int n) {
        this->n = n;
        m = 0;
        memset(G, 0, sizeof(G));
    }
    void AddEdge(int u, int v, int w) {
        edges[++m] = (Edge){u, v, w, G[u]};
        G[u] = m;
    }
    void dijkstra() {
        memset(vis, 0, sizeof(vis));
        while (!Q.empty()) {
            re Node head = Q.top(); Q.pop();
            int u = head.u;
            if (vis[u]) continue;
            vis[u] = 1;
            for (re int i = G[u]; i; i = edges[i].pre) {
                Edge &e = edges[i];
                if (!vis[e.v] && d[u] + e.w < d[e.v]) {
                    d[e.v] = d[u] + e.w;
                    Q.push((Node){e.v, d[e.v]});
                }
            }
        }
    }
} G;

int fx[4] = {0, 1, 0, -1};
int fy[4] = {1, 0, -1, 0};

int n, m, t;
int a[maxn][maxn], vis[maxn][maxn], dis[maxn][maxn];

void bfs(int X, int Y) {
    memset(dis, 0x3f, sizeof(dis));
    dis[X][Y] = 0;
    q.push((State){X, Y, 0});
    while (!q.empty()) {
        State head = q.front(); q.pop();
        dis[head.x][head.y] = head.d;
        rep(i, 0, 3) {
            re int x = head.x + fx[i], y = head.y + fy[i];
            if (a[x][y] && !vis[x][y]) {
                vis[x][y] = 1;
                dis[x][y] = head.d + 1;
                q.push((State){x, y, dis[x][y]});
            }
        }
    }
}

int main() {
    n = read(), m = read(), t = read();

    rep(i, 1, n)
        rep(j, 1, m)
            a[i][j] = read();

    G.init(n * n * 4);

    rep(X, 1, n)
        rep(Y, 1, m)
            if (a[X][Y]) {
                rep(i, 0, 3) {
                    re int x = X + fx[i], y = Y + fy[i];
                    if (a[x][y]) {
                        memset(vis, 0, sizeof(vis));
                        vis[x][y] = vis[X][Y] = 1;
                        bfs(x, y);
                        rep(j, 0, 3) {
                            re int x2 = X + fx[j], y2 = Y + fy[j];
                            if (i == j || !a[x2][y2]) continue;
                            G.AddEdge(convert(X, Y, i), convert(X, Y, j), dis[x2][y2]);
                        }
                    }
                }
                if (a[X][Y + 1]) G.AddEdge(convert(X, Y, 0), convert(X, Y + 1, 2), 1);
                if (a[X + 1][Y]) G.AddEdge(convert(X, Y, 1), convert(X + 1, Y, 3), 1);
                if (a[X][Y - 1]) G.AddEdge(convert(X, Y, 2), convert(X, Y - 1, 0), 1);
                if (a[X - 1][Y]) G.AddEdge(convert(X, Y, 3), convert(X - 1, Y, 1), 1);
            }

    re int Ex, Ey, Sx, Sy, Tx, Ty;

    while (t--) {
        Ex = read(), Ey = read(), Sx = read(), Sy = read(), Tx = read(), Ty = read();

        if (Sx == Tx && Sy == Ty) {
            printf("0\n");
            continue;
        }

        memset(vis, 0, sizeof(vis));
        vis[Ex][Ey] = vis[Sx][Sy] = 1;
        bfs(Ex, Ey);
        memset(G.d, 0x3f, sizeof(G.d));
        rep(i, 0, 3) {
            Q.push((Node){convert(Sx, Sy, i), dis[Sx + fx[i]][Sy + fy[i]]});
            G.d[convert(Sx, Sy, i)] = dis[Sx + fx[i]][Sy + fy[i]];
        }
        G.dijkstra();

        re int ans = inf;
        rep(i, 0, 3)
            if (a[Tx + fx[i]][Ty + fy[i]]) minn(ans, G.d[convert(Tx, Ty, i)]);
        if (ans == inf) printf("-1\n");
        else printf("%d\n", ans);
    }

    return 0;
}

帅哥美女们点个在再走吧球球了~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值