您的位置:首页 > 理论基础 > 计算机网络

洛谷 P1401 城市(二分+网络流)

2018-01-06 11:33 309 查看

题目描述

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


Solution:

  题目求的是最大边的最小值,可以下意识地想到二分答案,但是有限制条件(即从1到n的路径要大于等于t条)这时我们思考应该如何去check。可以很容易想到网络流吧(反正我是这样想的),因为题目中说了一条边只能用一次(这不就限制了容量嘛),而且可以把S当作1、T当作n,这样不就是求最大流啊,只要总流量大于t我们就将上界缩小,否则将下界增大,直到最后无法再check为止,输出ans就ok了。

  建图时,我们可以先保存边集数组,二分边界L赋值为1、R赋值为边的最大值,然后每次二分出mid值,若边长小于等于mid则加一条容量为1的边,check时就直接跑最大流就好了,最后输出ans题目解决。。

  注意:每次check记得清head数组并给cnt赋值。

代码:

#include<bits/stdc++.h>
#define il inline
#define debug printf("%d %s\n",__LINE__,__FUNCTION__)
using namespace std;
il int gi()
{
int a=0;char x=getchar();bool f=0;
while((x>'9'||x<'0')&&x!='-')x=getchar();
if(x=='-')x=getchar(),f=1;
while(x>='0'&&x<='9')a=a*10+x-48,x=getchar();
return f?-a:a;
}
const int N=100005,inf=233333;
int n,m,T,s,t=520,dis[400],h[500],cnt=1,ans;
struct edge{
int to,net,v;
}e[N*2],p
;
il void add(int u,int v,int w)
{
e[++cnt].to=v,e[cnt].net=h[u],e[cnt].v=w,h[u]=cnt;
e[++cnt].to=u,e[cnt].net=h[v],e[cnt].v=0,h[v]=cnt;
}
il bool bfs()
{
memset(dis,-1,sizeof(dis));
queue<int> q;
q.push(s),dis[s]=0;
while(!q.empty())
{
//    debug;
int u=q.front();q.pop();
for(int i=h[u];i;i=e[i].net)
if(dis[e[i].to]==-1&&e[i].v>0)
dis[e[i].to]=dis[u]+1,q.push(e[i].to);
}
return dis[t]!=-1;
}
il int dfs(int u,int op)
{
if(u==t)return op;
int flow=0,used=0;
for(int i=h[u];i;i=e[i].net)
{
int v=e[i].to;
if(dis[v]==dis[u]+1&&e[i].v>0)
{
used=dfs(v,min(op,e[i].v));
if(!used)continue;
flow+=used,op-=used;
e[i].v-=used,e[i^1].v+=used;
if(!op)break;
}
}
if(!flow)dis[u]=-1;
return flow;
}
il void add_edge(int x)
{
memset(h,0,sizeof(h));
cnt=1;
for(int i=1;i<=m;i++)
if(p[i].v<=x)add(p[i].to,p[i].net,1),add(p[i].net,p[i].to,1);

}
il bool check(int x)
{
add_edge(x);
int ans=0;
while(bfs())ans+=dfs(s,inf);
if(ans>=T)return 1;
return 0;
}
int main()
{
n=gi(),m=gi(),T=gi();
s=1,t=n;
int l=1,r=0;
for(int i=1;i<=m;i++)
p[i].to=gi(),p[i].net=gi(),p[i].v=gi(),r=max(r,p[i].v);
//    sort(p+1,p+m+1,cmp);
while(l<=r)
{
int mid=(l+r)/2;
if(check(mid))ans=mid,r=mid-1;
else l=mid+1;
}
cout<<ans;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: