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;
}版权声明:本文博主原创文章,博客,未经同意不得转载。
 
                    
                     
                    
                 
                    
                 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号