洛谷 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\n",__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 }
PS:~蒟蒻写博客不易,转载请注明出处,万分感谢!~