343E - Pumping Stations 最小割树
题意给一张流量网,问n-1天每天选不同的点,往任意未选过的点走管网输送流量使得能获得的流量和最大
输出流量和和输送序列
首先Gomory-Hu的定义和代码参考自这里
大体上就是从网络图上生成一棵树,树的性质满足两点路径最小边权等于两点在网络图上的最大流
有了这样一棵树就可以每次贪心选最小的一条边,保证现在边的两侧走完再走这条边
因为这样这条边就只走了一次,最小化了总流量的限制,然后两边分治
#include<bits/stdc++.h> #include<stdio.h> #include<algorithm> #include<queue> #include<string.h> #include<iostream> #include<math.h> #include<set> #include<map> #include<vector> #include<iomanip> using namespace std; #define ll long long #define pb push_back #define FOR(a) for(int i=1;i<=a;i++) const int inf=0x3f3f3f3f; const int maxn=200+9; struct EDGE{ int from,to,cap,flow; }; vector<EDGE>edges; vector<int>c[maxn]; int S,T; bool visit[maxn]; int depth[maxn]; int cur[maxn]; void clear_graph(){ edges.clear();for(int i=0;i<maxn;i++)c[i].clear(); } void clear_flow(){ int sz=edges.size(); for(int i=0;i<sz;i++)edges[i].flow=0; } void addedge(int from,int to,int cap){ EDGE tmp=(EDGE){from,to,cap,0}; edges.pb(tmp); tmp=(EDGE){to,from,cap,0}; edges.pb(tmp); int tot=edges.size()-2; c[from].pb(tot); c[to].pb(tot+1); } bool BFS(void){ memset(visit,0,sizeof(visit)); memset(depth,-1,sizeof(depth)); queue<int> Q; Q.push(S);visit[S]=true;depth[S]=0; while(!Q.empty()){ int x=Q.front();Q.pop(); for(int i=0;i<c[x].size();i++){ EDGE &now=edges[c[x][i]]; if(!visit[now.to]&&now.cap>now.flow){ visit[now.to]=true; depth[now.to]=depth[x]+1; Q.push(now.to); } } } return visit[T]; } int DFS(int x,int a){ if(x==T||!a) return a; int flow=0,cf=0; for(int i=cur[x];i<c[x].size();i++){ cur[x]=i; EDGE &now=edges[c[x][i]]; if(depth[x]+1==depth[now.to]){ cf=DFS(now.to,min(a,now.cap-now.flow)); if(cf){ flow+=cf; a-=cf; now.flow+=cf,edges[c[x][i]^1].flow-=cf; } if(!a) break; } } if(!flow) depth[x]=-1; return flow; } int Dinic(void){ int flow=0; while(BFS()){ memset(cur,0,sizeof(cur)); flow+=DFS(S,inf); } return flow; } int N,M; int fa[maxn],falen[maxn]; int now; void find_min(int x,int fa){ //找x子树中最小的边 for(int i=0;i<c[x].size();i++){ EDGE &e=edges[c[x][i]]; if(e.to!=fa && e.cap!=-1){ if(now==-1||e.cap<edges[now].cap)now=c[x][i]; find_min(e.to,x); } } } void solve(int x){ now=-1; find_min(x,0); if(now==-1){ printf("%d ",x); return; } edges[now].cap=edges[now^1].cap=-1; int p=now; solve(edges[p].from); solve(edges[p].to); } int ans=0; void build_tree(){ for(int i=1;i<=N;i++)fa[i]=1; for(int i=2;i<=N;i++){ clear_flow(); S=i,T=fa[i]; falen[i]=Dinic(); BFS(); for(int j=i+1;j<=N;j++) if(visit[j]&&fa[j]==fa[i])fa[j]=i; } clear_graph(); for(int i=2;i<=N;i++) addedge(i,fa[i],falen[i]),ans+=falen[i]; } void answer(){ printf("%d\n",ans); solve(1); puts(""); } void init(){ scanf("%d%d",&N,&M); int a,b,w; for(int i=1;i<=M;i++){ scanf("%d%d%d",&a,&b,&w); addedge(a,b,w); } } int main(){ init(); build_tree(); answer(); }