• USACO 2008 Jan. Silver/loj10074架设电话线


    题目地址

    第一步当然是分类:

    $1.$有一条从$1$到$n$的路径且路径经过的边的数量小于等于$k$,那么最小费用为$0$。

    判断方法:将所有边的边权设为$1$,进行并BFS,时间复杂度为$O(n)$。


    $2.$若所有从$1$到$n$的路径经过的边数均大于$k$,则求出所有路径上第$k+1$大的边的最小值。

    暴力做法明显会超时,注意到求第$k+1$的边的最值,似乎可以二分。

    judge函数的实现:

    若此时$(l+r)/2=ans$,我们要做的就是判断是否有一条从$1$到$n$的路径的第$k+1$条边小于等于$ans$。

    转化$ ightarrow$将所有边权小于$ans$的边的边权设为$0$,所有大于等于$ans$的边的边权设为$1$,检验更新边权后从$1$到$n$的最短路的长度是否小于等于$k$,是,则证明所有大于$ans$的数都可行,$r=ans$,否,则证明所有小于$ans$的数都不可行,$l=ans+1$。

    如何求更新边权后的图的最短路:

    注意到图的边权只有$0和1$,可以使用相比其它最短路算法更为高效的01BFS。

    01BFS:

    使用双端队列($deque$),若可以进行松弛操作且此时边权为$0$,进行松弛操作并将边指向的点加入队列头部,若可以进行松弛操作且此时边权为$1$,进行松弛操作并将边指向的点加入队列尾部。

    $Code:$

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #include <cstring>
    
    using namespace std;
    
    const int MAXN = 1010;
    
    int n, p, k, l = 0x7fffffff, r;
    deque<int> q;
    int head[MAXN], nxt[MAXN << 2], t[MAXN << 2], w[MAXN << 2], cnt;
    int step[MAXN];
    bool vis[MAXN];
    bool have = true;
    
    bool BFS() {
        q.push_back(1);
        step[1] = 1;
        while (!q.empty()) {
            int u = q.front();
            if (u == n) {
                while (!q.empty()) q.pop_front();
                if (step[u] <= k + 1)
                    return true;
                return false;
            }
            for (int i = head[u]; i; i = nxt[i]) {
                if (!step[t[i]]) {
                    step[t[i]] = step[u] + 1;
                    q.push_back(t[i]);
                }
            }
            q.pop_front();
        }
        have = false;
        return false;
    }
    
    bool judge(int cur) {
        memset(step, 0, sizeof(step));
        memset(vis, 0, sizeof(vis));
        q.push_back(1);
        vis[1] = true;
        for (int i = 1; i <= n; i++) {
            step[i] = 0x7fffffff;
        }
        step[1] = 0;
        while (!q.empty()) {
            int u = q.front();
            q.pop_front();
            if (u == n) {
                while (!q.empty()) q.pop_front();
                if (step[u] <= k)
                    return true;
                return false;
            }
            for (int i = head[u]; i; i = nxt[i]) {
                int len;
                if (w[i] <= cur)
                    len = 0;
                else
                    len = 1;
                if (step[u] + len < step[t[i]]) {
                    if (!len) {
                        q.push_front(t[i]);
                        step[t[i]] = step[u];
                    } else {
                        q.push_back(t[i]);
                        step[t[i]] = step[u] + 1;
                    }
                }
            }
        }
    }
    
    int binary_search() {
        l = 0;
        while (l != r) {
            int mid = (l + r) >> 1;
            bool ok = judge(mid);
            if (ok) {
                r = mid;
            } else {
                l = mid + 1;
            }
        }
        return l;
    }
    
    void addedge(int u, int v, int wei) {
        t[++cnt] = v;
        w[cnt] = wei;
        nxt[cnt] = head[u];
        head[u] = cnt;
        return;
    }
    
    int main() {
        scanf("%d%d%d", &n, &p, &k);
        for (int i = 1; i <= p; i++) {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            r = max(r, w);
            addedge(u, v, w);
            addedge(v, u, w);
        }
        BFS();
        if (!have) {
            puts("-1");
        } else
            printf("%d
    ", binary_search());
        return 0;
    }
  • 相关阅读:
    二、Java面向对象(11)_final修饰符
    二、Java面向对象(10)_代码块
    二、Java面向对象(9)_面向对象——多态思想
    二、Java面向对象(8)_继承思想——Object类
    二、Java面向对象(8)_继承思想——子类初始化过程
    二、Java面向对象(8)_继承思想——super关键字
    二、Java面向对象(8)_继承思想——方法覆盖
    WP8.1 RT 生命周期详解‏‏‏‏‏‏‏‏‏‏‏‏‏
    将十六进制色值转换成Color
    WindowsPhone8.1RT建立空白应用挂起没反应的解决方案
  • 原文地址:https://www.cnblogs.com/kjd123456/p/12454832.html
Copyright © 2020-2023  润新知