【ybtoj 宽搜进阶】【二分】A. 1.最小权值

A. 1.最小权值

ybtoj 宽搜进阶 A. 1.最小权值


题面

【ybtoj 宽搜进阶】【二分】A. 1.最小权值
【ybtoj 宽搜进阶】【二分】A. 1.最小权值


解题思路

二分,路径上最大的数
宽搜时加上条件,下一个点不能超过mid,就一定能保证这条路的最大值不大于mid
因为二分会不断缩减到正确答案,最后答案路径的最大值一定等于mid

可以重复走,可以发现只要能到第 n 行,那么第 n 行的所有点都可以走到
而且,本来题面也要求了必须要走第 n 行的所有点
但是怎样保证第 n 行的所有点的值,都不大于mid呢?
方法十分简单,只要把初始的最小值范围 l 改大,改成第 n 行的最大值


Code

#include <bits/stdc++.h>
#define N 1010

using namespace std;

const int w[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
int n, m, a[N][N], v[N][N], l, r, ans;
queue<pair<int, int> > q;

int che(int x, int y) {
	return (x >= 1 && x <= n && y >= 1 && y <= m);
}

int check(int maxn) {
	while(!q.empty()) q.pop();
	memset(v, 0, sizeof(v));
	
	for(int i = 1; i <= m; i ++) {  //第一行所有符合的点都加进去,走到第 n 行的可能性最大,也包含所有可能路径
		if(a[1][i] > maxn) continue;
		v[1][i] = 1, q.push(make_pair(1, i));
	}
	
	while(!q.empty()) {
		int x = q.front().first, y = q.front().second;
		q.pop();
		for(int i = 0; i < 4; i ++) {
			int xx = x + w[i][0], yy = y + w[i][1];
			if(!che(xx, yy) || a[xx][yy] > maxn || v[xx][yy]) continue;
			
			if(xx == n) return 1;
			v[xx][yy] = 1;
			q.push(make_pair(xx, yy));
		}
	}
	return 0;
}

int main() {
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; i ++)
		for(int j = 1; j <= m; j ++)
			scanf("%d", &a[i][j]);
		
	for(int i = 1; i <= m; i ++) l = max(l, a[n][i]);  //最小值范围改为第 n 行的最大值
	r = 1e4;
	while(l <= r) {
		int mid = (l + r) >> 1;
		if(check(mid)) 
			ans = mid, r = mid - 1;
		else l = mid + 1;
	}
	printf("%d", ans);
} 
上一篇:vi 常用快捷键


下一篇:logistic中交叉熵和均方差函数图像