zoukankan      html  css  js  c++  java
  • 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
    ");
            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
    ", l, s, e);
    }
    
    int main () {
        int cas;
        scanf("%d", &cas);
        while (cas--) {
            init();
            solve();
        }
        return 0;
    }

    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    BASIC-2 01字串
    BASIC-1 闰年判断
    BASIC-11 十六进制转十进制
    IO流之File类
    集合-下
    集合-上
    java常用类-下
    关于String的一些基础小题目
    java常用类-上
    异常
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4848464.html
Copyright © 2011-2022 走看看