首页 > 代码库 > zoj 3820 Building Fire Stations(二分+bfs)
zoj 3820 Building Fire Stations(二分+bfs)
题目链接:zoj 3820 Building Fire Stations
题目大意:给定一棵树,选取两个建立加油站,问说所有点距离加油站距离的最大值的最小值是多少,并且任意输出一种建立加油站的方式。
解题思路:二分距离判断,判断函数的复杂度是o(n),这样的复杂度应该是o(nlogn),即使常数系数偏大,但是居然跑了4.5s,也是醉了。
判断函数里面做了3次bfs,但是每次bfs节点最多遍历1次,首先任取一点做根建立一个树,找到深度最大的节点,以向上移动L(判断的ans)位置处的节点建立加油站,并以该点为根在建一棵树,这是第2次bfs,然后同样以最深的节点向上移动L次的节点建立加油站,判断这两个加油站使得所有节点距离加油站的值是否均小于等于L。
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 200005;
const int INF = 0x3f3f3f3f;
int M, first[maxn], jump[maxn * 2], edge[maxn * 2];
int N, s, e, far[maxn], dis[maxn];
queue<int> que;
inline void add_edge(int u, int v) {
edge[M] = v;
jump[M] = first[u];
first[u] = M++;
}
void init () {
int l, r;
M = 0;
scanf("%d", &N);
memset(first, -1, sizeof(first));
for (int i = 1; i < N; i++) {
scanf("%d%d", &l, &r);
add_edge(l, r);
add_edge(r, l);
}
}
int bfs(int s) {
que.push(s);
dis[s] = far[s] = 0;
int u;
while (!que.empty()) {
u = que.front();
que.pop();
for (int i = first[u]; i + 1; i = jump[i]) {
int v = edge[i];
if (dis[v] > dis[u] + 1) {
far[v] = u;
dis[v] = dis[u] + 1;
que.push(v);
}
}
}
return u;
}
bool judge (int L) {
memset(dis, INF, sizeof(dis));
s = bfs(1);
for (int i = 0; i < L; i++) {
s = far[s];
if (far[s] == 0) {
e = s % N + 1;
return true;
}
}
memset(dis, INF, sizeof(dis));
e = bfs(s);
for (int i = 0; i < L; i++) {
if (far[e] == 0)
return true;
e = far[e];
}
if (e == s)
e = e % N + 1;
bfs(e);
for (int i = 1; i <= N; i++)
if (dis[i] > L)
return false;
return true;
}
void solve () {
if (N == 2) {
printf("0 1 2\n");
return ;
}
int l = 0, r = N;
while (l < r) {
int mid = (l + r) / 2;
if (judge(mid))
r = mid;
else
l = mid + 1;
}
judge(l);
printf("%d %d %d\n", l, s, e);
}
int main () {
int cas;
scanf("%d", &cas);
while (cas--) {
init();
solve();
}
return 0;
}
zoj 3820 Building Fire Stations(二分+bfs)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。