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);
}