灾难预警(DFS+二分 / BFS+优先队列)

题目链接: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,如果能跑到 (n,n),可以从 mid 的右边继续找,如果不能则从左边找。

解法二:
用 bfs+优先队列,这样每次走都能走能走的点中海拔最高的那一个,再维护一个最小值,这样走到终点以后那个最小值就是所有路的最小值中最大的。


解法一代码
#include<bits/stdc++.h>
using namespace std;

int n,q;
int h[1007][1007];
int vis[1007][1007];
int water;
int dirx[4] = {0, 1, 0, -1};
int diry[4] = {1, 0, -1, 0};
int minn;
int getit;

void dfs(int x,int y)
{
	if(getit == 1) return;
	if(x == n && y == n)
	{
		getit = 1;
		return;
	}
	vis[x][y] = 1;
	for(int i=0;i<4;i++)
	{
		int xx = x + dirx[i];
		int yy = y + diry[i];
		if(vis[xx][yy] == 0 && xx >= 1 && xx <= n && yy >= 1 && yy <= n)
		{
			if(h[xx][yy] < minn)
			{
				continue;
			}
			dfs(xx, yy);
		}
	}
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    	for(int j=1;j<=n;j++)
    		scanf("%d",&h[i][j]);
    
    int l = 0, r = 100000;
    int ans;
    while(l <= r)//二分 
    {
    	memset(vis,0,sizeof(vis));
    	getit = 0;
    	minn = (l + r) / 2;
    	if(minn > h[1][1] || minn > h[n][n])
    	{
    		r = minn - 1;
    		continue;
		}
		dfs(1, 1);
		if(getit == 1)
			l = minn + 1, ans = minn;
		else
			r = minn - 1;
	}
    scanf("%d",&q);
    while(q--)
    {
    	scanf("%d",&water);
    	if(water > ans) printf("Hmmm\n");
    	else printf("Wuhu\n");
	}
    return 0;
}

解法二代码
#include<bits/stdc++.h>
using namespace std;

int n,q;
int h[1007][1007];
int vis[1007][1007];
int water;
int dirx[4] = {0, 1, 0, -1};
int diry[4] = {1, 0, -1, 0};
int minn;

struct node{
	int x,y;
	int hi;
	
	bool operator < (const node& b) const
	{
		return hi < b.hi;
	}
};

void bfs()
{
	priority_queue<node> q;
	node now;
	now.x = 1;
	now.y = 1;
	now.hi = h[1][1];
	q.push(now);
	while(!q.empty())
	{
		now = q.top();
		q.pop();
		if(now.x == n && now.y == n)
		{
			minn = now.hi;
			break;
		}
		if(vis[now.x][now.y] == 1) continue;
		vis[now.x][now.y] = 1;
		for(int i=0;i<4;i++)
		{
			int xx = now.x + dirx[i];
			int yy = now.y + diry[i];
			if(vis[xx][yy] == 1 || xx < 1 || xx > n || yy < 1 || yy > n) continue;
			node e;
			e.x = xx;
			e.y = yy;
			e.hi = min(h[xx][yy], now.hi);
			q.push(e);
		}
	}
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    	for(int j=1;j<=n;j++)
    		scanf("%d",&h[i][j]);
    bfs();
    //cout<<"minn----"<<minn<<endl;
    scanf("%d",&q);
    while(q--)
    {
    	scanf("%d",&water);
    	if(water > minn) printf("Hmmm\n");
    	else printf("Wuhu\n");
	}
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值