1. 程式人生 > >洛谷 P1401 城市(二分+網絡流)

洛谷 P1401 城市(二分+網絡流)

const names 二分答案 網絡 con turn div mes strong

題目描述

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 }

洛谷 P1401 城市(二分+網絡流)