NYOJ 306 - 走迷宫
传送门
思路
本来看着想DP的,发现不好写。
参考了题解。
竟然可以用二分差值 + DFS。涨姿势了
对差值进行二分,然后对于某个差值,确定出此时权值的最大值和最小值,再DFS。
代码
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int MAXN = 100 + 10;
const int INF = 0x3f3f3f3f;
const int dir[][2] = { {1, 0}, {-1, 0}, {0, 1}, {0, -1} };
int mp[MAXN][MAXN], vis[MAXN][MAXN], vmax, vmin, n;
bool DFS(int x, int y, int l, int r)
{
if (x == n && y == n)
return true;
int i, j;
for (i = 0; i < 4; i++)
{
int xx = x + dir[i][0];
int yy = y + dir[i][1];
if (xx >= 1 && xx <= n && yy >= 1 && yy <= n && !vis[xx][yy])
{
if (mp[xx][yy] < l || mp[xx][yy] > r)
continue;
vis[xx][yy] = 1;
if (DFS(xx, yy, l, r))
return true;
}
}
return false;
}
bool Solve(int mid)
{
int i, j;
for (i = vmin; i <= vmax - mid; i++)
{
memset(vis, 0, sizeof vis);
bool flag = false;
if (mp[1][1] < i || mp[1][1] > i + mid)
continue;
if (mp[n][n] < i || mp[n][n] > i + mid)
continue;
vis[1][1] = 1;
if (DFS(1, 1, i, i + mid))
return true;
}
return false;
}
int BSearch()
{
int l = abs(mp[1][1] - mp[n][n]), r = vmax - vmin, mid;
while (l < r)
{
mid = l + (r - l) / 2;
Solve(mid) ? r = mid : l = mid + 1;
}
return r;
}
int main()
{
//freopen("input.txt", "r", stdin);
int i, j;
while (~scanf("%d", &n))
{
memset(vis, 0, sizeof vis);
vmax = -1, vmin = INF;
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
{
scanf("%d", ∓[i][j]);
vmax = max(vmax, mp[i][j]);
vmin = min(vmin, mp[i][j]);
}
printf("%d\n", BSearch());
}
return 0;
}