【纪中集训2019.3.26】完美理论

题目

题面

给出节点个数为(n)两棵树,点的权值都相同为(a_i);

要求选出一些点(S),使得在两颗树上都是一个连通块;

最大化(S)的点权;

(T)组数据;

范围

$1 le T le 50 , 1 le n le 100 , |a_i| le 1000 $;

题解

  • 典型的网络流范围;

  • 确定一个根之后,选一个点必须选一个点的父亲;

  • 做最大权闭合子图即可;

  • 复杂度:(O(Tn^4));

    #include<bits/stdc++.h>
    #define inf 0x3f3f3f3f
    using namespace std;
    const int N=410;
    int n,m,a[N],o,hd[N],preO,preH[N],cur[N],vis[N],d[N],ans;
    struct Edge{int v,nt,f;}E[N<<1],preE[N<<1];
    queue<int>q;
    char gc(){
    	static char*p1,*p2,s[1000000];
    	if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
    	return(p1==p2)?EOF:*p1++;
    }
    int rd(){
    	int x=0,f=1;char c=gc();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
    	while(c>='0'&&c<='9'){x=x*10+c-'0';c=gc();}
    	return x*f;
    }
    void init(){
    	o=preO;for(int i=0;i<=n+1;++i)hd[i]=preH[i];
    	for(int i=0;i<o;++i)E[i]=preE[i];
    }
    void adde(int u,int v,int c){
    	E[o]=(Edge){v,hd[u],c};hd[u]=o++;
    	E[o]=(Edge){u,hd[v],0};hd[v]=o++;
    }
    struct Tree{
    	int o,hd[N],fa[N];
    	struct Edge{int v,nt;}E[N<<1];
    	void init(){o=1;for(int i=1;i<=n;++i)hd[i]=0;}
    	void adde(int u,int v){
    		E[o]=(Edge){v,hd[u]};hd[u]=o++;
    		E[o]=(Edge){u,hd[v]};hd[v]=o++; 
    	}
    	void dfs(int u,int F){
    		fa[u]=F;
    		for(int i=hd[u];i;i=E[i].nt){
    			int v=E[i].v;
    			if(v==F)continue;
    			dfs(v,u);
    		}
    	}
    }T1,T2;
    bool bfs(){
    	for(int i=0;i<=n+1;++i)vis[i]=d[i]=0;
    	while(!q.empty())q.pop();
    	q.push(0);vis[0]=d[0]=1;
    	while(!q.empty()){
    		int u=q.front();q.pop();
    		for(int i=hd[u];~i;i=E[i].nt)if(E[i].f){
    			int v=E[i].v;
    			if(vis[v])continue;
    			vis[v]=1;d[v]=d[u]+1;q.push(v);
    			if(v==n+1)return true;
    		}
    	}
    	return false;
    }
    int dfs(int u,int F){
    	if(u==n+1||!F)return F;
    	int flow=0,f;
    	for(int i=cur[u];~i;i=E[i].nt){
    		int v=E[cur[u]=i].v;
    		if(d[v]==d[u]+1&&(f=dfs(v,min(E[i].f,F)))){
    			flow+=f;F-=f;
    			E[i].f-=f;E[i^1].f+=f;
    			if(!F)break;
    		}
    	}
    	return flow;
    }
    int main(){
    //	freopen("noname.in","r",stdin);
    //	freopen("noname.out","w",stdout);
    	int T=rd();
    	while(T--){
    		n=rd();
    		o=0;for(int i=0;i<=n+1;++i)hd[i]=-1;
    		int preAns=0;
    		for(int i=1;i<=n;++i){
    			a[i]=rd();
    			if(a[i]<0)adde(i,n+1,-a[i]);
    			else adde(0,i,a[i]),preAns+=a[i];
    		}
    		preO=o;for(int i=0;i<=n+1;++i)preH[i]=hd[i];
    		for(int i=0;i<o;++i)preE[i]=E[i];
    		T1.init();for(int i=1;i<n;++i)T1.adde(rd(),rd());
    		T2.init();for(int i=1;i<n;++i)T2.adde(rd(),rd());
    		ans=0;
    		for(int i=1;i<=n;++i){
    			init();
    			T1.dfs(i,0);
    			T2.dfs(i,0);
    			for(int i=1;i<=n;++i){
    				adde(i,T1.fa[i],inf);
    				adde(i,T2.fa[i],inf);
    			}	
    			int tmp=preAns;
    			while(bfs()){
    				for(int i=0;i<=n+1;++i)cur[i]=hd[i];
    				tmp-=dfs(0,inf);
    			}
    			ans=max(ans,tmp);
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
原文地址:https://www.cnblogs.com/Paul-Guderian/p/10602025.html