1. 程式人生 > >P1948 [USACO08JAN]電話線Telephone Lines(二分答案+最短路)

P1948 [USACO08JAN]電話線Telephone Lines(二分答案+最短路)

思路

考慮題目要求求出最小的第k+1大的邊權,想到二分答案

然後二分第k+1大的邊權wx

把所有邊權<=wx的邊權變為0,邊權>wx的邊權變為0,找出最短路之後,如果dis[T]<=k,則答案可行,反之則不可行

似乎有dp解法的樣子,真神奇

程式碼

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
int dis[1100],u[11000<<1],v[11000<<1],w[11000<<1],n,p,k,fir[11000<<1],nxt[11000<<1],cnt;
void addedge(int ui,int vi,int wi){
    ++cnt;
    u[cnt]=ui;
    v[cnt]=vi;
    w[cnt]=wi;
    nxt[cnt]=fir[ui];
    fir[ui]=cnt;
}
bool check(int mid){
    memset(dis,0x3f,sizeof(dis));
    deque<int> q;
    q.push_back(1);
    dis[1]=0;
    while(!q.empty()){
        int x=q.front();
        q.pop_front();
        for(int i=fir[x];i;i=nxt[i]){
            if(dis[x]+(w[i]>mid)<dis[v[i]]){
                dis[v[i]]=dis[x]+(w[i]>mid);
                if(w[i]>mid)
                    q.push_back(v[i]);
                else
                    q.push_front(v[i]);
            }
        }
    }
    return dis[n]<=k;
}
int main(){
    scanf("%d %d %d",&n,&p,&k);
    for(int i=1;i<=p;i++){
        int a,b,c;
        scanf("%d %d %d",&a,&b,&c);
        addedge(a,b,c);
        addedge(b,a,c);
    }
    int l=0,r=1000100,ans=-1;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid)){
            ans=mid;
            r=mid-1;
        }
        else
            l=mid+1;
    }
    printf("%d",ans);
    return 0;
}