• [USACO 2008 Jan. Silver]架设电话线 —— 最短路+二分


    一道图论的最短路题。一开始连最短路都没想到,可能是做的题太少了吧,完全没有思路。

    题目大意:
    FJ的农场周围分布着N根电话线杆,任意两根电话线杆间都没有电话线相连。一共P对电话线杆间可以拉电话线,第i对电话线杆的两个端点分别为A_i、B_i,它们间的距离为L_i 。数据中保证每对{A_i,B_i}最多只出现1次。FJ的任务是找一条将1号和N号电话线杆连起来的路径。电信公司最终同意免费为FJ连结任意K对电话线杆。此外的电话线,FJ需要为它们付的费用,等于其中最长的电话线的长度(每根电话线仅连结一对电话线杆)。如果需要连结的电话线杆不超过K对,那么FJ的总支出为0。求FJ最少需要在电话线上花多少钱,如果任务不可能完成,输出-1。

    1 <= N <= 1,000
    1 <= P <= 10,000
    1 <= L_i <= 1,000,000
    0 <= K < N
    样例输入
    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

    注意一句话题意 : 在加权无向图上求出一条从 1号结点到n号结点的路径,使路径上第k+1大的边权尽量小。”

    我们不妨将这条k+1大的边权设为(P),将图中大于等于(P)的边权类似离散的思想的将它们赋为1,反之赋为0。这里就不给出图了。我们再对离散后的图跑一遍最短路,设这时1-n的最短路长度为(X),我们便可以发现(P)在这条最短录径上第(X+1)的边(因为比(P)大的边只有(X)条)

    试问,如果这个(X)(K+1)还大,请问这个(P)还可以作为我们的答案吗?肯定是不行的,因为我们跑的是最短路,也就是(X)最小的情况,如果这个(X)(K+1)还大,那么这条边(P)就不可能是(K+1)大的边,自然就会舍去。

    现在要解决的是(P)的问题,直接枚举吗?其实根本不需要,我们发现如果(P)跑出来的最短路小于等于(K),那么(P+1)跑出来的最短路也一定小于等于(K),答案明显满足单调性,因此我们可以使用二分来做这道题。

    (有的人可能要为为什么是小于等于(K),按照一句话题意不是要我们求(X)等于(K)的情况。我的理解是有的路径的条数可能比(K)还少,但我们依然可以选择这条路径上的边。另外,这样也适应了二分的情况。如果是等于,二分则跑不出来。)

    关于对图的离散化,不要告诉我们你们会直接把所有边都赋为1和0,在代码中我们只需要这么做(我用的是dijkstra的堆优化)

    			v=G[now.u][i].v,w=G[now.u][i].w;
                if(w>=P) w1=1;
                else w1=0;
                if(dis[now.u]+w1<dis[v]) {
                    dis[v]=dis[now.u]+w1;
                    q.push( node (dis[v],v));
                }
    

    代码

    #include <iostream>
    #include <cstdio>
    #include <vector>
    #include <algorithm>
    #include <stack>
    #include <cstring>
    #include <queue>
    using namespace std;
    
    #define N 50010
    #define inf 0x7f7f7f7f
    
    struct node {
        int u,dis;
        node () {};
        node (int D,int U) { u=U; dis=D; }
        bool operator < (const node& h) const {
    		return dis>h.dis;
    	}
    };
    
    struct Gragh {
        int v,w;
        Gragh () {};
        Gragh (int V,int W) {v=V;w=W;}
    };
    
    int P[10],n,m,k,ans=inf,vis[N],sum=1,dis[N];
    vector<Gragh> G[N];
    priority_queue<node> q;
    
    int dijkstra(int st,int P) {
        q.push( node (0,st) );
        memset(dis,0x3f,sizeof(dis));
        dis[st]=0;
        memset(vis,0,sizeof(vis));
        while(!q.empty() ) {
            node now=q.top();
            q.pop();
            if(vis[now.u]) continue;
            vis[now.u]=1;
            for(int i=0,v,w,w1;i<G[now.u].size();i++) {
                v=G[now.u][i].v,w=G[now.u][i].w;
                if(w>=P) w1=1;
                else w1=0;
                if(dis[now.u]+w1<dis[v]) {
                    dis[v]=dis[now.u]+w1;
                    q.push( node (dis[v],v));
                }
            }
        }
        return dis[n];
    }
    
    bool check(int mid) {
        if(dijkstra(1,mid)<=k) return 1;
        return 0;
    }
    
    /*
    4 3 3
    1 2 1
    2 3 2
    3 4 3
    */
    
    int main() {
        int maxw=0;
        cin>>n>>m>>k;
        for(int i=1,u,v,w;i<=m;i++) {
            cin>>u>>v>>w;
            maxw=max(maxw,w);
            G[u].push_back( Gragh(v,w) );
            G[v].push_back( Gragh(u,w) );
        }
        int mid,l=0,r=maxw,flag=0;
        while(l<r) {
            mid=(l+r+1)/2;
            if(check(mid)) r=mid-1,flag=1;
            else l=mid;
        }
        if(!flag) cout<<"-1";
        else cout<<l;
    }
    

    (话说二分每次都打不对orz)

  • 相关阅读:
    20189317 《网络攻防技术》 第四周作业
    20189317 《网络攻防技术》 第三周作业
    20189317 《网络攻防技术》 第二周作业
    2018-2019-2 20189317 《网络攻防技术》 第一周作业
    20189311《网络攻防》第十周作业
    20189311《网络攻防》第九周作业
    20189311《网络攻防》第八周作业
    20189311《网络攻防》第七周作业
    20189311《网络攻防》第六周作业
    20189311《网络攻防》第五周作业
  • 原文地址:https://www.cnblogs.com/MisakaMKT/p/11252279.html
Copyright © 2020-2023  润新知