浙江农林大学第十九届程序设计竞赛暨天梯赛选拔赛(同步赛)——灾难预警(二分 + dfs解题)

11 篇文章 0 订阅
11 篇文章 0 订阅

链接:https://ac.nowcoder.com/acm/contest/7872/M
来源:牛客网
 

题目描述


    众所周知,浙农林是一条河。
    由于浙江农林大学的特殊地形,当你在下雨后漫步在农林大路上的时候
    难免会出现一脚踩进一个水坑的情况的情况。而农农非常不喜欢踩到水坑的感觉,
    请你帮忙设计一个程序来帮助农农判断他能否在不踩入水坑的情况下回到
    寝室。
    
    已知,浙江农林大学可以表示为一个 N * N 的矩阵。
    对于每个位置有一个海拔数据 h[i][j],当水位高度大于 h[i][j] 的时候,

    这个位置就会形成一个水坑。

    农农现在的坐标是 (1, 1), 他的宿舍位于 (n, n).

    农农只可以沿着上下左右四个方向走。

    假如农农现在位于 (2, 2)那么在不考虑水位的情况下,他可以去的地方有 

  (1, 2),(2,1), (3, 2)    ,(2, 3)

    

输入描述:

    N (表示矩阵大小)
    接下来 N 行为一个 N * N 的矩阵 h
    Q (表示询问数量)
    接下来 Q 行每行一个数字,表示当前水位 X 
    
    1 <= N <= 1000
    1 <= h[i][j] <= 100000
    1 <= X <= 100000
    1 <= Q <= 100000

输出描述:

    共 Q 行,表示在对应水位下,农农能否在不踩入水坑的情况下
    回到寝室, 如果农农可以回到寝室,请你输出“Wuhu”, 反之请输出
    “Hmmm” 

示例1

输入

 

4 
5 2 3 2
4 5 3 4
2 1 4 5
3 3 3 3
2
1
5

输出

 

Wuhu
Hmmm

说明

 

对于第一次询问,没有任何一个位置形成水坑,所以农农可以从(1, 1)走到(4, 4)

对于第二次询问 高度小于 5 的位置形成了水坑,其中包括目的地 (4, 4)所以农农无法在

不踩到水坑的情况下走到(4, 4)

 

 


 

 

比赛的时候因为我做题实在太少了,结果当每给一个水位,我就跑一遍dfs,那肯定是超时了...

后面受到大佬的启发,原来是得先用二分 + dfs 做一遍预处理才行,二分的目的是为了找出最优路,最优路的选择利用了短板效应,也就是最优路里最小的海拔一定大于等于其它别的路里最小的海拔,最优路所能满足的最大水位高度肯定是最高的,找出那个临界水位值

然后小于等于那个临界水位的,都可以从左上角走到右下角;大于那个临界水位就没法从左上角走到右下角了 。

 

二分模板代码1

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1010;
int h[maxn][maxn];
int vis[maxn][maxn];
int n;

void dfs(int x, int y, int mid) {
	if (x < 1 || x > n || y < 1 || y > n || h[x][y] < mid || vis[x][y]) return;

	vis[x][y] = 1;
	dfs(x - 1, y, mid);
	dfs(x + 1, y, mid);
	dfs(x, y - 1, mid);
	dfs(x, y + 1, mid);
}

int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			scanf("%d", &h[i][j]);

	int level = 1;
	int left = 1, right = 100000; //left一开始为最小的水位高度,right一开始为最大的水位高度
	while (left <= right) {
		memset(vis, 0, sizeof(vis));
		int mid = left + (right - left) / 2;
		dfs(1, 1, mid);
		if (vis[n][n]) { //看看是否能够抵达右下角
			level = mid;
			left = mid + 1; //看看还能不能再大
		} else {
			right = mid - 1; //说明抵达不了右下角,得缩小水位的值
		}
	}

	int q, temp;
	scanf("%d", &q);
	while (q--) {
		scanf("%d", &temp);
		if (temp <= level) cout << "Wuhu" << endl;
		else cout << "Hmmm" << endl;
	}

	return 0;
}

 

 

二分模板代码2

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1010;
int h[maxn][maxn];
int vis[maxn][maxn];
int n;

void dfs(int x, int y, int mid) {
	if (x < 1 || x > n || y < 1 || y > n || h[x][y] < mid || vis[x][y]) return;

	vis[x][y] = 1;
	dfs(x - 1, y, mid);
	dfs(x + 1, y, mid);
	dfs(x, y - 1, mid);
	dfs(x, y + 1, mid);
}

int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			scanf("%d", &h[i][j]);

	int level = 1;
	int left = 1, right = 100000; //left一开始为最小的水位高度,right一开始为最大的水位高度
	while (left < right) {
		memset(vis, 0, sizeof(vis));
		int mid = left + (right - left) / 2;
		dfs(1, 1, mid);
		if (vis[n][n]) { //看看是否能够抵达右下角
			level = mid;
			left = mid + 1; //看看还能不能再大
		} else {
			right = mid; //说明抵达不了右下角,得缩小水位的值
		}
	}

	int q, temp;
	scanf("%d", &q);
	while (q--) {
		scanf("%d", &temp);
		if (temp <= level) cout << "Wuhu" << endl;
		else cout << "Hmmm" << endl;
	}

	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

重剑DS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值