【GMOJ 1403】【Vijos 1468】 渡河

题目大意:

传说中教主乃世外高人,不屑于参加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);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值