zoukankan      html  css  js  c++  java
  • 【纪中集训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;
      }
      
  • 相关阅读:
    win7下64位系统memcache/memcached安装教程
    支付宝接口使用文档说明 支付宝异步通知(notify_url)与return_url.
    PHP使用DES进行加密解密
    使用PHP对文件进行压缩解压(zip)
    发一个天气预报接口
    使用php发送电子邮件(phpmailer)
    在线支付接口详解
    php 操作数组 (合并,拆分,追加,查找,删除等)
    PHP5中魔术方法
    Ehlib 学习
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/10602025.html
Copyright © 2011-2022 走看看