感谢怀哥提供的经典好题,让我学会了二分答案这个思想! //二分答案+最大流 //终于见识到传说中的二分答案这个方法了 //如果没有二分答案这个提示,这道题我怎么也不会往最大流去想 //思路是这样的,将所有边权值排序,记录边权值的上界和下界 //接着开始二分答案,依照枚举的这个答案构图,即将边权值最大值小于等于枚举的这个答案的边加进图中 //(双向边)并将他们的容量设为1,有多重边就将容量再+1,接着FF最大流,如果最大流>=T,则说明答案是满足条件的 //记住此时未必是正确答案,答案还可以再小。继续二分,知道最终答案出来 //二分后最终答案是下界,即程序中的l,而不是mid中间值!记得~~因为这个WA了几次 #include<iostream> #include<queue> #include<vector> using namespace std; const int MAXN = 205,MAXM = 40005; const int INF = 2147483647; struct Edge { int u,v,w; Edge(int uu,int vv,int ww) { u = uu; v = vv; w = ww; } }; int rflow[MAXN],flow[MAXN][MAXN],cap[MAXN][MAXN],pre[MAXN]; int l,r,mid,maxflow; int N,T,P; vector<Edge> E; void buildGraph(int ans) { memset(cap,0,sizeof(cap)); for(int i = 0;i < E.size();++i) { if(E[i].w <= ans) { cap[E[i].u][E[i].v] += 1; cap[E[i].v][E[i].u] += 1; } } } void FF()//FF模板 { queue<int> q; memset(flow,0,sizeof(flow)); maxflow = 0; while(1) { memset(rflow,0,sizeof(rflow)); rflow[1] = INF; q.push(1); while(!q.empty()) { int u = q.front(); q.pop(); for(int v = 1;v <= N;++v) if(rflow[v] == 0 && cap[u][v] > flow[u][v]) { pre[v] = u; q.push(v); rflow[v] = min(rflow[u],cap[u][v] - flow[u][v]); } } if(rflow[N] == 0) break; for(int u = N;u != 1;u = pre[u]) { flow[pre[u]][u] += rflow[N]; flow[u][pre[u]] -= rflow[N]; } maxflow += rflow[N]; } } int main() { //freopen("in.txt","r",stdin); int u,v,w; scanf("%d%d%d",&N,&P,&T); l = INF; r = -INF; while(P--) { scanf("%d%d%d",&u,&v,&w); if(w < l) l = w; if(w > r) r = w; E.push_back(Edge(u,v,w)); } while(l <= r) { mid = (r+l) / 2; buildGraph(mid); FF(); if(maxflow >= T) r = mid - 1; else l = mid + 1; } printf("%d/n",l); return 0; }