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$。

转化$\rightarrow$将所有边权小于$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\n", binary_search());
    return 0;
}

 

posted @ 2020-03-10 12:00  kjd123456  阅读(154)  评论(0编辑  收藏  举报