POJ3662Telephone Lines(最短路+二分)

传送门

题目大意:n个点p条边,每条边有权值,让1和n点联通,可以将联通1--n的边选k条免费,

求剩下边权的最大值。

题解:二分一个答案x,大于x的边权设为1,小于等于x的边权设为0,跑最短路。

若从1到n的最短路dis[n]<=k,则可以通过免费k条边,答案为x。

代码:

#include<iostream>
#include<cstdio>
#include<queue> 
#include<cstring>
#include<algorithm>
#define N 1009
#define M 10009
using namespace std;

int n,p,k;

int sumedge;

int head[N],dis[N],vis[N];

queue<int>q;

struct Edge
{
    int x,y,z,nxt;
    Edge(int x=0,int y=0,int z=0,int nxt=0):
        x(x),y(y),z(z),nxt(nxt){}
}edge[M<<1];

void add(int x,int y,int z)
{
    edge[++sumedge]=Edge(x,y,z,head[x]);
    head[x]=sumedge;
}

bool ok(int tp)
{
    while(!q.empty()) q.pop();
    memset(dis,0x3f,sizeof(dis));
    q.push(1);vis[1]=true;dis[1]=0;
    while(!q.empty())
    {
        int now=q.front();q.pop(); vis[now]=false;
        for(int i=head[now];i;i=edge[i].nxt)
        {
            int v=edge[i].y;
            if(dis[v]>dis[now]+(edge[i].z<=tp?0:1))
            {
                dis[v]=dis[now]+(edge[i].z<=tp?0:1);
                if(!vis[v])
                {
                    vis[v]=true;
                    q.push(v); 
                }
            }
        }
    } 
    return dis[n]<=k;
}

int main()
{
    scanf("%d%d%d",&n,&p,&k);
    int l=0,r=0,ans=-1;
    for(int i=1;i<=p;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);add(y,x,z);
        r=max(r,z);
    }
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(ok(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    }
    cout<<ans<<endl;
    return 0;
} 

猜你喜欢

转载自www.cnblogs.com/zzyh/p/11990749.html