[USACO Jan08][BZOJ 1614][COGS 147]架设电话线

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/CoolKid_cwm/article/details/52727765

题目

题目大致意思是给一张无向图,每条边有边权,有k条边可以把边权设为0,求一条路径使
路径上的最大的边权最小。

一般情况下最大值最小或最小值最大可以用二分去解,此题不例外。
我们二分答案x把边权大于x的边边权设为1,跑SPFA,求出最短路,比较k与最短路径如果
k>distance_min 那么答案可以更小,否则,答案必须变大。

Code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;

const int MAXN=1001;
const int INF=2147483647;

struct Edge{
    int from,to,dist,flag;
};
vector<Edge> edges;
vector<int> G[MAXN];

void Addedge(int f,int t,int d){
    edges.push_back((Edge){f,t,d});
    int m=edges.size();
    G[f].push_back(m-1);
}

int d[MAXN];
bool inq[MAXN];
int m,n;
int k;

bool SPFA(int x){
    for(int i=0;i<edges.size();i++) edges[i].flag=edges[i].dist>x;
    memset(inq,false,sizeof(inq));
    queue<int> q;
    for(int i=2;i<=n;i++) d[i]=INF;
    q.push(1);
    inq[1]=true;
    while(!q.empty()){
        int u=q.front();q.pop();
        inq[u]=false;
        for(int i=0;i<G[u].size();i++){
            Edge &e=edges[G[u][i]];
            if(d[e.to]>d[u]+e.flag){
                d[e.to]=d[u]+e.flag;
                if(!inq[e.to]) q.push(e.to),inq[e.to]=true;
            }
        }
    }
    return d[n]<=k;
}

void init(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=0;i<m;i++){
        int f,t,d;
        scanf("%d%d%d",&f,&t,&d);
        Addedge(f,t,d);
        Addedge(t,f,d);
    }
}

int main(){
    freopen("phoneline.in","r",stdin);
    freopen("phoneline.out","w",stdout);
    init();
    SPFA(0);
    if(d[n]==INF){
        printf("-1\n");
        return 0;
    }
    int L=0,R=1000000;
    while(L<R){
        int mid=(L+R)>>1;
        if(SPFA(mid)) R=mid;
        else L=mid+1;
    }
    printf("%d\n",L);
    #ifdef DEBUG
        while(1);
    #endif
    return 0;
}
展开阅读全文

没有更多推荐了,返回首页