一张无向图中有 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; }