【纪中集训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\n",ans);
      }
      return 0;
    }

猜你喜欢

转载自www.cnblogs.com/Paul-Guderian/p/10602025.html
今日推荐