• 架设电话线 题解


    题目描述

    原题来自:USACO 2008 Jan. Silver

    在郊区有 (N) 座通信基站,(P) 条双向电缆,第 (i) 条电缆连接基站 (A_i)(B_i)。特别地,(1) 号基站是通信公司的总站,(N) 号基站位于一座农场中。现在,农场主希望对通信线路进行升级,其中升级第 (i) 条电缆需要花费 (L_i)

    电话公司正在举行优惠活动。农场主可以指定一条从 (1) 号基站到 (N) 号基站的路径,并指定路径上不超过 (K) 条电缆,由电话公司免费提供升级服务。农场主只需要支付在该路径上剩余的电缆中,升级价格最贵的那条电缆的花费即可。求至少用多少钱能完成升级。

    一句话题意,在加权无向图上求出一条从 (1) 号结点到 (N) 号结点的路径,使路径上第 (K + 1) 大的边权尽量小。

    输入格式

    第一行三个整数 (N, P, K).

    接下来 (P) 行,每行三个整数 (A_i, B_i, L_i).

    输出格式

    若不存在从 (1)(N) 的路径,输出 -1。否则输出所需最小费用。

    样例输入

    5 7 1
    1 2 5
    3 1 4
    2 4 8
    3 2 3
    5 2 9
    3 4 7
    4 5 6
    

    样例输出

    4
    

    分析

    看到最大的最小?那一定是二分。看到第 (K) 大的最小?显然这还是二分。

    我们可以直接二分答案。然后每次 (check) 答案的时候,将所有的大于这个值的边的权值改为 (1),其余的改为 (0)。其实就是标记了一下比当前枚举答案大的。

    然后跑最短路,如果最短路跑出来小于 (K) 则说明满足一条路径上二分的这个答案是第 (K + 1) 大的,反之则说明当前枚举的答案不是可行解。继续二分。

    接下来我们看看详细复杂,啰嗦,累赘的代码。

    AC代码

    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    int n, p, k;
    struct edge {  // 结构体 边
        int v, cost;
        edge() {}
        edge(int V, int Cost) {
            v = V;
            cost = Cost;
        }
    };
    const int MAXN = 2005;
    const int INF = 0x3f3f3f3f;
    vector<edge> graph[MAXN];
    int ma = 0;
    bool flag = true;
    int dist[MAXN];
    bool vis[MAXN];
    vector<edge> mp[MAXN];
    
    void read(int &x) {  // 读优
        int k = 1;
        x = 0;
        char s = getchar();
        while (s < '0' || s > '9') {
            if (s == '-')
                k = -1;
            s = getchar();
        }
        while (s >= '0' && s <= '9') {
            x = (x << 1) + (x << 3) + (s - '0');
            s = getchar();
        }
        x *= k;
        return;
    }
    
    void Add_Edge(int u, int v, int cost) {  // 存边
        graph[u].push_back(edge(v, cost));
        graph[v].push_back(edge(u, cost));
    }
    
    void init(int x) {  // 初始化
        for (int i = 1; i <= n; i++) mp[i].clear();
        memset(dist, 0x3f, sizeof dist);
        memset(vis, 0, sizeof vis);
        for (int i = 1; i <= n; i++)
            for (int j = 0; j < graph[i].size(); j++) {
                int V = graph[i][j].v;
                int Cost = graph[i][j].cost;
                if (Cost > x) { // 跑最短路时的"01"图
                    mp[i].push_back(edge(V, 1));
                    mp[V].push_back(edge(i, 1));
                } else {
                    mp[i].push_back(edge(V, 0));
                    mp[V].push_back(edge(i, 0));
                }
            }
        //	for(int i = 1; i <= n; i++)
        //		for(int j = 0; j < mp[i].size(); j++)
        //			printf("%d %d %d
    ", i, mp[i][j].v, mp[i][j].cost);
        return;
    }
    
    int dijkstra(int x) {  // dijkstra
        init(x);
        dist[1] = 0;
        for (int i = 1; i <= n; i++) {
            int k = 0, mi = INF;
            for (int j = 1; j <= n; j++)
                if (!vis[j] && dist[j] < mi) {
                    mi = dist[j];
                    k = j;
                }
            vis[k] = true;
            for (int j = 0; j < mp[k].size(); j++) {
                int V = mp[k][j].v, Cost = mp[k][j].cost;
                if (dist[k] + Cost < dist[V])
                    dist[V] = dist[k] + Cost;
            }
        }
        return dist[n];
    }
    
    bool check(int mid) {  // 二分 判断可行性函数
        int t = dijkstra(mid);
        if (t == INF) {
            flag = false;
            return false;
        }
        if (t > k)
            return false;
        return true;
    }
    
    int Find() {  // 二分
        int l = 0, r = ma;
        while (l < r) {
            int mid = (l + r) >> 1;
            if (check(mid))
                r = mid;
            else {
                if (flag == false)
                    return -1;
                l = mid + 1;
            }
        }
        return l;
    }
    
    int main() {
        read(n); read(p); read(k);
        for (int i = 1; i <= p; i++) {
            int u, v, cost;
            read(u); read(v); read(cost);
            Add_Edge(u, v, cost);
            ma = max(ma, cost);
        }
        printf("%d
    ", Find());
        return 0;
    }
    
  • 相关阅读:
    Ghost Button制作教程及设计趋势分析
    onhashchange事件--司徒正美
    window.location.hash属性介绍
    优质UI的7条准则(一)
    当在浏览器地址栏输入一个网址的时候,究竟发生了什么?
    全球最快的JS模板引擎
    眨眼登录表单
    DIV+CSS规范命名
    es6--export,import
    es6--class
  • 原文地址:https://www.cnblogs.com/Chain-Forward-Star/p/13868298.html
Copyright © 2020-2023  润新知