题目描述
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


看到题目的最大的最小,应该不难想到二分。

但是二分怎么check呢?怎么快速判断当前的mid是否和法呢?

可能因为自己对网络流比较收悉吧,看到T条路,然后我们就想到了网络流的流量,我们每次重新加边,加小于等于mid的边,就可以保证一定不会有大于mid的边权了,然后判断最大流是否大于t。若大于t就是有解的,不然就无解,改变二分区间。


AC代码:

#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=210,M=16e4+10;
int n,m,t,h[N],a[M],b[M],c[M];
int head[N],nex[M],to[M],w[M],tot;
inline void ade(int a,int b,int c){
	to[++tot]=b; w[tot]=c; nex[tot]=head[a]; head[a]=tot;
}
inline void add(int a,int b,int c){
	ade(a,b,c);	ade(b,a,0);
}
int bfs(){
	memset(h,0,sizeof h);	queue<int> q;	q.push(1);	h[1]=1;
	while(q.size()){
		int u=q.front();	q.pop();
		for(int i=head[u];i;i=nex[i]){
			if(w[i]&&!h[to[i]]){
				h[to[i]]=h[u]+1;	q.push(to[i]);
			}
		}
	}
	return h[n];
}
int dfs(int x,int f){
	if(x==n)	return f;	int fl=0;
	for(int i=head[x];i&&f;i=nex[i]){
		if(w[i]&&h[to[i]]==h[x]+1){
			int mi=dfs(to[i],min(w[i],f));
			w[i]-=mi;	w[i^1]+=mi;	fl+=mi;	f-=mi;
		}
	}
	if(!fl)	h[x]=-1;
	return fl;
}
int dinic(){
	int res=0;
	while(bfs())	res+=dfs(1,inf);
	return res;
}
inline int check(int mid){
	memset(head,0,sizeof head);	tot=1;
	for(int i=1;i<=m;i++)	if(c[i]<=mid)	add(a[i],b[i],1),add(b[i],a[i],1);
	return dinic()>=t;
}
int bsearch(){
	int l=1,r=100000;
	while(l<r){
		int mid=l+r>>1;
		if(check(mid))	r=mid;
		else	l=mid+1;
	}
	return l;
}
int main(){
	cin>>n>>m>>t;
	for(int i=1;i<=m;i++)	cin>>a[i]>>b[i]>>c[i];
	cout<<bsearch()<<endl;
	return 0;
}