洛谷 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

Solution:

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

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

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

代码:

 1 #include<bits/stdc++.h>
 2 #define il inline
 3 #define debug printf("%d %s
",__LINE__,__FUNCTION__)
 4 using namespace std;
 5 il int gi()
 6 {
 7     int a=0;char x=getchar();bool f=0;
 8     while((x>'9'||x<'0')&&x!='-')x=getchar();
 9     if(x=='-')x=getchar(),f=1;
10     while(x>='0'&&x<='9')a=a*10+x-48,x=getchar();
11     return f?-a:a;
12 }
13 const int N=100005,inf=233333;
14 int n,m,T,s,t=520,dis[400],h[500],cnt=1,ans;
15 struct edge{
16 int to,net,v;
17 }e[N*2],p[N];
18 il void add(int u,int v,int w)
19 {
20     e[++cnt].to=v,e[cnt].net=h[u],e[cnt].v=w,h[u]=cnt;
21     e[++cnt].to=u,e[cnt].net=h[v],e[cnt].v=0,h[v]=cnt;
22 }
23 il bool bfs()
24 {
25     memset(dis,-1,sizeof(dis));
26     queue<int> q;
27     q.push(s),dis[s]=0;
28     while(!q.empty())
29     {
30     //    debug;
31         int u=q.front();q.pop();
32         for(int i=h[u];i;i=e[i].net)
33         if(dis[e[i].to]==-1&&e[i].v>0)
34         dis[e[i].to]=dis[u]+1,q.push(e[i].to);
35     }
36     return dis[t]!=-1;
37 }
38 il int dfs(int u,int op)
39 {
40     if(u==t)return op;
41     int flow=0,used=0;
42     for(int i=h[u];i;i=e[i].net)
43     {
44         int v=e[i].to;
45         if(dis[v]==dis[u]+1&&e[i].v>0)
46         {
47             used=dfs(v,min(op,e[i].v));
48             if(!used)continue;
49             flow+=used,op-=used;
50             e[i].v-=used,e[i^1].v+=used;
51             if(!op)break;
52         }
53     }
54     if(!flow)dis[u]=-1;
55     return flow;
56 }
57 il void add_edge(int x)
58 {
59     memset(h,0,sizeof(h));
60     cnt=1;
61     for(int i=1;i<=m;i++)
62         if(p[i].v<=x)add(p[i].to,p[i].net,1),add(p[i].net,p[i].to,1);
63 
64 }
65 il bool check(int x)
66 {
67     add_edge(x);
68     int ans=0;
69     while(bfs())ans+=dfs(s,inf);
70     if(ans>=T)return 1;
71     return 0;
72 }
73 int main()
74 {
75     n=gi(),m=gi(),T=gi();
76     s=1,t=n;
77     int l=1,r=0;
78     for(int i=1;i<=m;i++)
79         p[i].to=gi(),p[i].net=gi(),p[i].v=gi(),r=max(r,p[i].v);
80 //    sort(p+1,p+m+1,cmp);
81     while(l<=r)
82     {
83         int mid=(l+r)/2;
84         if(check(mid))ans=mid,r=mid-1;
85         else l=mid+1;
86     }
87     cout<<ans;
88     return 0;
89 }
原文地址:https://www.cnblogs.com/five20/p/8213732.html