题目大意:
传说中教主乃世外高人,不屑于参加OI竞赛,于是云游四方,威风八面。只不过教主行踪不定,就像传说中的神兽一样可遇而不可求。小L和小H为了求得教主签名的Orz教主T-Shirt,打算碰碰运气展开了冒险。在冒险中,他们不幸被突来的洪水冲到了一个神秘丛林中,他们想尽快逃出这个地方。小L找到了一张看似为曾经的冒险者遗弃的地图,但经过探查,地图所示的确实是这片丛林。小L从地图上看到,有众多河流穿过这片丛林,等到他接近一条最近的河流时,发现水流较急,且河水很深,小H不擅长游泳,所以他们决定利用丛林中的树木做一只竹筏渡河。
虽然竹筏做好后可以在这一条河所连通的水域任意行进,但是竹筏在上岸后必须抛弃,若想再次渡河必须再做一次竹筏,但这毕竟是十分辛苦的,他们希望做竹筏也就是渡河的次数尽量少,就求助于你。
地图上的陆地和河流可以抽象成一个n*n由数字0和1组成的矩阵,其中0代表陆地,1代表河流。无论在陆地上还还是河流上,他们都可以向相邻8格(边相邻或角相邻)移动,但是若要从陆地进入河流(也就是从0到1),则必须制作竹筏。若到达地图边界则顺利逃脱。但是小T和小K有可能迷路,所以会多次询问你,对于每次询问,只要输出到达地图边界需要的最少渡河次数即可,保证每次询问都是指向陆地。
小L和小H翻到地图的反面,赫然发现六个大字:“教主到此一游”!两人无法抑制自己激动的心情,将这张地图珍藏起来。据说后来这张图成为无价之宝。
解题思路:
陆地和河流分层bfs求出每个点到边的渡河次数
A c c e p t e d c o d e : Accepted\ code: Accepted code:
#include<cstdio>
#include<iostream>
using namespace std;
const int N = 1005;
const int M = 1000005;
const int dx[8] = {0, 0, 1, -1, 1, -1, 1, -1};
const int dy[8] = {1, -1, 0, 0, 1, -1, -1, 1};
int n, q;
char c[N][N];
int a[N][N], v[N][N], sx[M], sy[M], sx1[M], sy1[M], cost[N][N];
inline int read() {
int f = 0; char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) f = f * 10 + c - 48, c = getchar();
return f;
}
bool check(int x, int y) {
return v[x][y] || x < 0 || y < 0 || x > n + 1 || y > n + 1;
}
void find() {
int h1 = 2, t1 = 1;
while (t1) {
int t = t1, h = 0; t1 = 0;
while (h <= t) {
++h;
for (int i = 0; i < 8; ++i) {
int x = sx[h] + dx[i];
int y = sy[h] + dy[i];
if (check(x, y)) continue;
v[x][y] = 1;
if (a[x][y] == a[sx[1]][sy[1]])
sx[++t] = x, sy[t] = y, cost[x][y] = h1; else
sx1[++t1] = x, sy1[t1] = y, cost[x][y] = h1 + 1;
}
}
++h1;
for (int i = 0; i <= t1; ++i)
sx[i] = sx1[i], sy[i] = sy1[i];
}
}
int main() {
n = read(), q = read();
for (int i = 1; i <= n; ++i)
scanf("%s", c[i] + 1);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
a[i][j] = c[i][j] - 48;
find();
for (int i = 1; i <= q; ++i) {
int x = read(), y = read();
printf("%d ", (cost[x][y] >> 1) - 1);
}
}