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();
}



posted @ 2017-09-21 01:13  Drenight  阅读(130)  评论(0编辑  收藏  举报