11373: 【原1373】收集红旗比赛
题目
题目描述
author: wkn/ssy 原OJ链接:https://acm.sjtu.edu.cn/OnlineJudge-old/problem/1373
Description
“年轻人啊,都是靡靡之音呐,都是轻歌曼舞呐,将来都是没有出息的。这个啊,就是要豪迈,比如要比赛爬山啊,比赛拔河啊。”
于是wkn毅然投入到了爬山比赛中(其实是为了素拓)。
这座山可以看做一个M x N的矩阵,矩阵里的每一项代表当前位置山的高度。
在山上插着好几面红旗,参赛选手可以选择任何一面红旗所在的点出发,目标是经过所有插红旗的地方。 wkn当然想获胜,于是就要找出一种方案,使得在爬山的过程中,任意相邻位置的海拔差的最大值最小。 但是他最近被毕业论文逼得焦头烂额没时间写代码计算了,情你帮帮他。
Input Format
第一行为两个整数M,N(M,N不超过500)
接下里M*N表示每个位置山的高度
接下里M*N表示每个位置上是否有红旗
Output Format
一行一个整数,表示最打海拔差的最小值
Input Sample
2 3
0 1 9
4 2 9
1 0 0
0 1 0
Output Sample
1
FineArtz's solution
/* 收集红旗比赛 */
#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
const int INF = 2147483647;
const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};
class Point{
public:
Point() = default;
Point(int xx, int yy) : x(xx), y(yy) {}
bool operator ==(Point p){
return (x == p.x && y == p.y);
}
int x = 0, y = 0, minh = INF;
};
int h[505][505];
bool v[505][505];
vector<Point> fl;
int m, n;
int ans = 0, cnt = 0;
bool check(Point p){
if (p.x < 1 || p.x > m || p.y < 1 || p.y > n || v[p.x][p.y]) return false;
return true;
}
bool bfs(Point s, int lim){
memset(v, 0, sizeof(v));
queue<Point> q;
q.push(s);
v[s.x][s.y] = true;
while (!q.empty()){
Point now = q.front();
q.pop();
for (int i = 0; i != 4; ++i){
Point next(now.x + dx[i], now.y + dy[i]);
if (check(next)){
int dh = abs(h[now.x][now.y] - h[next.x][next.y]);
if (dh > lim) continue;
q.push(next);
v[next.x][next.y] = true;
}
}
}
for (auto f : fl){
if (!v[f.x][f.y]) return false;
}
return true;
}
int main(){
memset(h, 0, sizeof(h));
cin >> m >> n;
int minn = INF, maxx = 0;
for (int i = 1; i <= m; ++i)
for (int j = 1; j <= n; ++j){
cin >> h[i][j];
minn = min(minn, h[i][j]);
maxx = max(maxx, h[i][j]);
}
int flag;
for (int i = 1; i <= m; ++i)
for (int j = 1; j <= n; ++j){
cin >> flag;
if (flag == 1){
fl.emplace_back(i, j);
}
}
Point s = *(fl.begin());
fl.erase(fl.begin());
s.minh = 0;
int low = 0, high = maxx - minn, mid = (low + high) / 2;
while (low < high){
mid = (low + high) / 2;
if (bfs(s, mid))
high = mid;
else
low = mid + 1;
}
cout << low << endl;
return 0;
}
yyong119's solution
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define max(x, y) ((x) > (y) ? (x) : (y))
#define min(x, y) ((x) < (y) ? (x) : (y))
#define MAX_N 505
using namespace std;
struct data {
int height;
bool flag;
} a[MAX_N][MAX_N];
struct Node {
int x, y;
Node(int p = 0, int q = 0): x(p), y(q) {}
}s;
const int step[4][2] = {{0, -1}, {-1, 0}, {1, 0}, {0, 1}};
int n, m, cnt, l, r, rest;
bool vis[MAX_N][MAX_N];
queue<Node> q;
inline int read() {
char ch = getchar(); int res = 0;
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9')
res = (res << 3) + (res << 1) + (ch ^ 48), ch = getchar();
return res;
}
inline void clear(queue<Node> &q) {
queue<Node> empty;
swap(empty, q);
}
bool check(const int& delta_height) {
while (!q.empty() && rest) {
Node cur = q.front(); q.pop();
for (int i = 0; i < 4; ++i) {
Node next(cur.x + step[i][0], cur.y + step[i][1]);
if (next.x >= 0 && next.x < n && next.y >= 0 && next.y < m &&
!vis[next.x][next.y] && abs(a[next.x][next.y].height - a[cur.x][cur.y].height) <= delta_height) {
vis[next.x][next.y] = true;
if (a[next.x][next.y].flag) --rest;
q.push(next);
}
}
}
if (rest) return false;
else return true;
}
int main() {
n = read(), m = read();
for (register int i = 0; i < n; ++i)
for (register int j = 0; j < m; ++j) {
a[i][j].height = read();
r = max(r, a[i][j].height);
}
for (register int i = 0; i < n; ++i)
for (register int j = 0; j < m; ++j) a[i][j].flag = read();
for (register int i = 0; i < n; ++i)
for (register int j = 0; j < m; ++j)
if (a[i][j].flag) {
s.x = i, s.y = j;
++cnt;
}
l = 0;
while (l < r) {
int mid = (l + r) >> 1;
clear(q); q.push(s);
memset(vis, false, sizeof(vis)); vis[s.x][s.y] = true;
rest = cnt - 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
printf("%d", l);
return 0;
}