Luogu P1401 城市(二分+网络流)

P1401 城市

题意

题目描述

N(2<=n<=200)个城市,M(1<=m<=40000)条无向边,你要找T(1<=T<=200)条从城市1到城市N的路,使得最长的边的长度最小,边不能重复用。

输入输出格式

输入格式:

第1行三个整数N,M,T用空格隔开。

第2行到P+1行,每行包括三个整数Ai,Bi,Li表示城市Ai到城市Bi之间有一条长度为Li的道路。

输出格式:

输出只有一行,包含一个整数,即经过的这些道路中最长的路的最小长度。

输入输出样例

输入样例#1:

7 9 2
1 2 2
2 3 5
3 7 5
1 4 1
4 3 1
4 5 7
5 7 1
1 6 3
6 7 3

输出样例#1:

5

思路

这道题可以用并查集做。 --alecli

每条边最多走一遍,不就相当于对图跑一遍网络流,流量必须大于等于\(T\)吗?所以我们可以二分答案,对原图跑网络流,判断流量是否满足要求。

AC代码

#include<bits/stdc++.h>
using namespace std;
int n,m,t,ans,L=INT_MAX,R,cur[205],dep[205];
int cnt=1,top[205],to[160005],len[160005],cap[160005],rcap[160005],nex[160005];
int read()
{
    int re=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
    return re;
}
bool bfs(int lim)
{
    memset(cur,0,sizeof cur);
    memset(dep,0,sizeof dep);
    cur[1]=top[1],dep[1]=1;
    queue<int>Q;
    Q.push(1);
    while(!Q.empty())
    {
        int now=Q.front();Q.pop();
        for(int i=cur[now];i;i=nex[i])
            if(!dep[to[i]]&&len[i]<=lim&&cap[i])
            {
                cur[to[i]]=top[to[i]],dep[to[i]]=dep[now]+1;
                Q.push(to[i]);
            }
    }
    return dep[n]!=0;
}
int dfs(int now,int flow,int lim)
{
    if(now==n) return flow;
    int re=0;
    for(int &i=cur[now];i;i=nex[i])
        if(dep[to[i]]==dep[now]+1&&len[i]<=lim&&cap[i])
        {
            int lzq=dfs(to[i],min(flow,cap[i]),lim);
            if(lzq)
            {
                re+=lzq,flow-=lzq;
                cap[i]-=lzq,cap[i^1]+=lzq;
                if(!flow) break;
            }
        }
    return re;
}
bool check(int lim)
{
    int tmp=0;
    for(int i=1;i<=cnt;i++) cap[i]=rcap[i];
    while(bfs(lim)) tmp+=dfs(1,INT_MAX,lim);
    return tmp>=t;
}
int main()
{
    n=read(),m=read(),t=read();
    while(m--)
    {
        int x=read(),y=read(),z=read();
        to[++cnt]=y,len[cnt]=z,cap[cnt]=rcap[cnt]=1,nex[cnt]=top[x],top[x]=cnt;
        to[++cnt]=x,len[cnt]=z,cap[cnt]=rcap[cnt]=0,nex[cnt]=top[y],top[y]=cnt;
        to[++cnt]=y,len[cnt]=z,cap[cnt]=rcap[cnt]=0,nex[cnt]=top[x],top[x]=cnt;
        to[++cnt]=x,len[cnt]=z,cap[cnt]=rcap[cnt]=1,nex[cnt]=top[y],top[y]=cnt;
        L=min(L,z),R=max(R,z);
    }
    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;
}
posted @ 2018-10-19 18:11  UranusITS  阅读(163)  评论(0编辑  收藏  举报