• Codeforces 343E Pumping Stations


    Description

    题面
    题目大意:求一个排列 (P),使得 (sum_{i=1}^{n-1}maxflow(P_i,P_{i+1})) 尽量大

    Solution

    构造出最小割树,那么第一问答案就是最小割树的边权和
    之前我对最小割树都理解错了
    实际上这么一个过程:
    1.从当前集合中任选两个点 ((x,y)) 作为源汇点,跑最小割,然后连边 ((x,y,maxflow))
    2.把原集合由割边分为两个集合,递归处理,并且要把上一个集合的 (T),作为这个集合的 (S) ,这样才能保证连成一棵树
    3.直到点集只有一个点时,返回

    构出来的树满足性质:
    原图中 ((x,y)) 的最小割,就是树中 ((x,y)) 路径中的最小边权

    然后考虑如何构造一种方案使得最大流之和最大
    首先我们肯定要让最小边走最少的次数,那么我们就只需要尽量不经过这条边就可以了(因为这条边权值是最小的,所以经过了就一定会算一次这条边的贡献)
    于是就产生了这么一个做法:
    找到权值最小边,把这条边断开分为两个集合,继续递归,直到集合大小为(1)时,我们把点加入到排列中
    这样排列中的点就分为了两部分 ((x1,x2,x3..xn)),((y1,y2,y3...yn)),(x,y) 分别对应这条边两端的点的集合

    这样做下去,边权小的边经过的次数我们已经最小化了,但是发现还是不可避免的会经过一次
    所以我们得出结论:所有的边都恰好经过一次,这样就得到了第一问的答案

    第二问的答案也可以通过模拟这个过程得出

    #include<bits/stdc++.h>
    #define pb push_back
    using namespace std;
    const int N=205,M=4005,inf=2e8;
    struct sub{int x,y,z;}e[M];int b[N];
    int n,m,id[N],dep[N],S,T,head[N],nxt[M],to[M],dis[M];
    int num=1,ans=0,Head[N],NUM=1,TO[M],DIS[M]={inf},NXT[M];
    inline void link(int x,int y,int z){
    	nxt[++num]=head[x];to[num]=y;head[x]=num;dis[num]=z;
    	nxt[++num]=head[y];to[num]=x;head[y]=num;dis[num]=z;
    }
    inline void Link(int x,int y,int z){
    	NXT[++NUM]=Head[x];TO[NUM]=y;Head[x]=NUM;DIS[NUM]=z;
    	NXT[++NUM]=Head[y];TO[NUM]=x;Head[y]=NUM;DIS[NUM]=z;
    }
    inline bool bfs(){
    	queue<int>Q;
    	memset(dep,0,sizeof(dep));
    	dep[S]=1;Q.push(S);
    	while(!Q.empty()){
    		int x=Q.front();Q.pop();
    		for(int i=head[x];i;i=nxt[i]){
    			int u=to[i];
    			if(dep[u] || dis[i]<=0)continue;
    			dep[u]=dep[x]+1;Q.push(u);
    		}
    	}
    	return dep[T];
    }
    inline int dfs(int x,int flow){
    	if(x==T || !flow)return flow;
    	int u,tmp,tot=0;
    	for(int i=head[x];i;i=nxt[i]){
    		u=to[i];
    		if(dep[u]!=dep[x]+1 || dis[i]<=0)continue;
    		tmp=dfs(u,min(flow,dis[i]));
    		dis[i]-=tmp;dis[i^1]+=tmp;
    		flow-=tmp;tot+=tmp;
    		if(!flow)break;
    	}
    	if(!tot)dep[x]=-1;
    	return tot;
    }
    inline int maxflow(int tx,int ty){
    	S=tx;T=ty;
    	int tot=0,t;
    	while(bfs()){
    		t=dfs(S,inf);
    		while(t)tot+=t,t=dfs(S,inf);
    	}
    	return tot;
    }
    inline void Clear(){memset(head,0,sizeof(head));num=1;}
    inline void solve(int l,int r){
    	if(l==r)return ;
    	Clear();
    	for(int i=1;i<=m;i++)link(e[i].x,e[i].y,e[i].z);
    	int t=maxflow(id[l],id[r]),L=l-1,R=r+1;
    	ans+=t;Link(id[l],id[r],t);
    	for(int i=l;i<=r;i++)
    		if(dep[id[i]])b[++L]=id[i];else b[--R]=id[i];
    	reverse(b+L+1,b+R+1); //为了保证形成一棵树,id[r] 这个点必须作为下一层的 id[l]
    	for(int i=l;i<=r;i++)id[i]=b[i];
    	solve(l,L);solve(R,r);
    }
    bool vis[M];int maxid=0;
    inline void BFS(int x,int last){
    	for(int i=Head[x];i;i=NXT[i]){
    		if(TO[i]==last || vis[i])continue;
    		if(DIS[i]<DIS[maxid])maxid=i;
    		BFS(TO[i],x);
    	}
    }
    inline void Deal(int x){
    	maxid=0;BFS(x,x);
    	if(maxid==0){printf("%d ",x);return ;}
    	vis[maxid]=vis[maxid^1]=1;
    	int u=TO[maxid],v=TO[maxid^1];
    	Deal(u);Deal(v);
    }
    int main(){
      freopen("pp.in","r",stdin);
      freopen("pp.out","w",stdout);
      scanf("%d%d",&n,&m);
      for(int i=1;i<=m;i++)scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);
      for(int i=1;i<=n;i++)id[i]=i;
      solve(1,n);
      printf("%d
    ",ans);
      Deal(1);
      return 0;
    }
    
    
  • 相关阅读:
    DELL、HP、IBM X86服务器命名规则
    容灾,热备,集群等区别
    HDS(日立)AMS2000系列存储管理配置方法
    KBMMW 4.90.00 发布
    delphi 10 seattle 安卓服务开发(三)
    delphi 10 seattle 安卓服务开发(二)
    delphi 10 seattle 中 解决IOS 9 限制使用HTTP 服务问题
    Android 中的 Service 全面总结(转载)
    KBMMW 4.84.00 发布
    delphi 10 seattle 安卓服务开发(一)
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8494024.html
Copyright © 2020-2023  润新知