题意:给定一个矩阵,从左上角到右下角,使走过的路径中数字的最大值最小值之差最小,问差最小是多少。
分析:首先不能用bfs,priority_queue以下两组数据可以说明问题。
有时候不能先扩展最优的。
2
5 6
1 1
3
5 6 1
1 3 5
1 7 1
正确的方法是二分这个差值a,对于每个二分结果枚举范围d~d+a,然后进行bfs,只有矩阵上的数字在d到d+a之间的格子才可以走。看能否到达终点。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define maxn 115
struct Node
{
int x, y;
} q[maxn * maxn];
int n, u, d;
int map[maxn][maxn];
bool vis[maxn][maxn];
int dir[4][2] =
{
{ 1, 0 },
{ 0, 1 },
{ -1, 0 },
{ 0, -1 } };
void input()
{
u = 0;
d = maxn;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
{
scanf("%d", &map[i][j]);
d = min(map[i][j], d);
u = max(map[i][j], u);
}
}
bool ok(Node &a, int u, int d)
{
if (a.x < 0 || a.y < 0 || a.x >= n || a.y >= n)
return false;
return !vis[a.x][a.y] && map[a.x][a.y] <= u && map[a.x][a.y] >= d;
}
bool bfs(int d, int u)
{
q[0].x = 0;
q[0].y = 0;
int front = 0;
int rear = 1;
memset(vis, 0, sizeof(vis));
vis[0][0] = true;
while (front != rear)
{
Node temp = q[front++];
if (front == maxn * maxn)
front = 0;
for (int i = 0; i < 4; i++)
{
Node a;
a.x = temp.x + dir[i][0];
a.y = temp.y + dir[i][1];
if (ok(a, u, d))
{
q[rear++] = a;
if (rear == maxn * maxn)
rear = 0;
vis[a.x][a.y] = true;
}
}
}
return vis[n - 1][n - 1];
}
bool reach(int a)
{
for (int i = max(max(d, map[n - 1][n - 1] - a), map[0][0] - a); i <= min(
min(u - a, map[0][0]), map[n - 1][n - 1]); i++)
if (bfs(i, i + a))
return true;
return false;
}
void binarysearch()
{
int l = abs(map[n - 1][n - 1] - map[0][0]);
int r = u - d;
while (l < r)
{
int mid = (l + r) / 2;
if (reach(mid))
r = mid;
else
l = mid + 1;
}
printf("%d\n", l);
}
int main()
{
//freopen("t.txt", "r", stdin);
scanf("%d", &n);
input();
binarysearch();
return 0;
}