一张无向图中有 N 个点,M 条边,每条边都有一个权值,且每条边只能用一次,要求找出 T 条从 1 到 N 的路径,使这 T 条路径所经过的边中,权值的最大值最小。
思想:二分边权值上线,多次构图求最大流,判断max_flow是否满足 T 。详见代码:
#include<cstdio>
#include<cstring>
#include<queue>
#define find_min(a,b) a<b?a:b
#define find_max(a,b) a>b?a:b
using namespace std;
const int N = 210;
const int MAX = (int)10e7;
struct Edge{
int s,e,v,next;
}edge[2*N*N],mat[N*N];
int e_num,head[N],d[N],sp,tp;
int n,m;
void AddEdge(int a,int b,int c){
edge[e_num].s=a; edge[e_num].e=b; edge[e_num].v=c;
edge[e_num].next=head[a]; head[a]=e_num++;
edge[e_num].s=b; edge[e_num].e=a; edge[e_num].v=c;
edge[e_num].next=head[b]; head[b]=e_num++;
}
int bfs(){
queue <int> q;
memset(d,-1,sizeof(d));
d[sp]=0;
q.push(sp);
while(!q.empty()){
int cur=q.front();
q.pop();
for(int i=head[cur];i!=-1;i=edge[i].next){
int u=edge[i].e;
if(d[u]==-1 && edge[i].v>0){
d[u]=d[cur]+1;
q.push(u);
}
}
}
return d[tp] != -1;
}
int dfs(int a,int b){
int r=0;
if(a==tp)return b;
for(int i=head[a];i!=-1 && r<b;i=edge[i].next){
int u=edge[i].e;
if(edge[i].v>0 && d[u]==d[a]+1){
int x=find_min(edge[i].v,b-r);
x=dfs(u,x);
r+=x;
edge[i].v-=x;
edge[i^1].v+=x;
}
}
if(!r)d[a]=-2;
return r;
}
int dinic(int sp,int tp){
int total=0,t;
while(bfs()){
while(t=dfs(sp,MAX))
total+=t;
}
return total;
}
void init(int index){
int i,j;
e_num=0;
memset(head,-1,sizeof(head));
for(i=1;i<=m;i++){
if(mat[i].v<=index)AddEdge(mat[i].s,mat[i].e,1);
}
}
int main()
{
int t_num,i,j,a,b,c;
while(~scanf("%d%d%d",&n,&m,&t_num)){
sp=1;tp=n;
int high=-1,low=MAX;
for(i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
high=find_max(high,c);
low=find_min(low,c);
mat[i].s=a; mat[i].e=b; mat[i].v=c;
}
int mid,ans;
while(low<=high){
mid=(low+high)/2;
init(mid);
ans=dinic(sp,tp);
if(ans<t_num)low=mid+1;
else high=mid-1;
}
printf("%d\n",low);
}
return 0;
}