zoukankan      html  css  js  c++  java
  • Codeforces Round #523 (Div. 2) E. Politics(最小费+思维建图)

    https://codeforces.com/contest/1061/problem/E

    题意

    有n个点(<=500),标记第i个点的代价a[i],然后分别在这n个点建两棵树,对于每颗树的每个点来说,都有一个p[i],代表他的子树中被标记的点的个数需要等于p[i],请你选择需要标记的点,使得可以满足上述两棵树的要求,并且使得代价最大,输出最大的代价或者-1(不存在)

    思路

    • 这道题难在建图
    • 首先考虑子树问题,是否选择每个节点对他的子孙节点没有影响,但是对他自身及其祖先节点有影响,注意p[i]=0代表i的子树没有限制

      假设v为u的子孙节点且p[u]>0(有限制),sum=p[v1]+p[v2]+..+p[vn],
      sum>p[u],则对于本棵树来说不存在满足条件的选点情况
      sum<=p[u],则剩下p[u]-sum的空间给本棵树和另外一颗树选择

    • 设col[u]为最靠近u的有限制的祖先节点(包括u),那么选择u就等于填充了两棵树的col[u]节点
    • 所以可以这样建图,建超源超汇S,T,将第一颗树的点和源点相连,cap=p[u]-sum,cost=0,将第二颗树的点和汇点相连,cap=p[u]-sum,cost=0,将两棵树之间的点col1[u]和col2[u]相连,cap=1,cost=-a[u],跑一个mcmf
    • 还需要判一下左边容量等于右边容量并且最大流等于容量,才能存在满足条件的选点情况
    #include<bits/stdc++.h>
    #define N 2005
    #define M 4000000
    #define inf 0x3f3f3f3f
    using namespace std;
    int n,rt1,rt2,ent,S,T,i,u,v,q,x,hd[N],p[N],col[N],f[N],d[N],inq[N],pre[N],a[N];
    int flow,cost,ans,in,out;
    
    struct edge{
        int u,v,nt,c,w;
        edge(int u=0,int v=0,int nt=0,int c=0,int w=0):u(u),v(v),nt(nt),c(c),w(w){}
    }E[M];
    
    void fail(){
        cout<<-1;exit(0);
    }
    void add(int u,int v,int c,int w){
        E[++ent]=edge(u,v,hd[u],c,w);hd[u]=ent;
        E[++ent]=edge(v,u,hd[v],0,-w);hd[v]=ent;
    }
    int dfs(int u,int fa,int tar){
        if(p[u])tar=u;
        col[u]=tar;
        int cnt=0,tp=p[u];
        for(int i=hd[u];i;i=E[i].nt){
            int v=E[i].v;
            if(v==fa)continue;
            cnt+=dfs(v,u,tar);
        }
        if(p[u]){if(p[u]<cnt)fail();p[u]-=cnt;cnt=tp;}
        return cnt;
    }
    
    int bf(){
        queue<int>Q;
        for(i=0;i<=T;i++)d[i]=inf;
        memset(inq,0,sizeof(inq));
        d[S]=0;inq[S]=1;pre[S]=0;f[S]=inf;Q.push(S);
    
        while(!Q.empty()){
            int u=Q.front();Q.pop();
            inq[u]=0;
            for(int i=hd[u];i;i=E[i].nt){
                edge &e=E[i];
                if(e.c&&d[e.v]>d[u]+e.w){
                    d[e.v]=d[u]+e.w;
                    pre[e.v]=i;
                    f[e.v]=min(f[u],e.c);
                    if(!inq[e.v]){inq[e.v]=1;Q.push(e.v);}
                }
            }
        }
        return d[T]<inf;
    }
    
    void mcmf(){
        if(in!=out)fail();
        flow=0;cost=0;
        while(bf()){
            flow+=f[T];cost-=d[T]*f[T];
            for(int i=T;i!=S;i=E[pre[i]].u){
                E[pre[i]].c-=f[T];
                E[pre[i]^1].c+=f[T];
            }
        }
        if(flow!=in)fail();
        cout<<cost<<endl;
    }
    
    int main(){
        cin>>n>>rt1>>rt2;rt2+=n;
        ent=1;S=2*n+1;T=2*n+2;
        for(i=1;i<=n;i++)scanf("%d",&a[i]);
        for(i=0;i<n-1;i++){scanf("%d%d",&u,&v);add(u,v,0,0);}
        for(i=0;i<n-1;i++){scanf("%d%d",&u,&v);u+=n;v+=n;add(u,v,0,0);}
        cin>>q;
        for(i=0;i<q;i++){scanf("%d%d",&u,&x);p[u]=x;}
        cin>>q;
        for(i=0;i<q;i++){scanf("%d%d",&u,&x);p[u+n]=x;}
        dfs(rt1,0,rt1);dfs(rt2,0,rt2);
    
        memset(hd,0,sizeof(hd));ent=1;
        in=out=0;
        for(i=1;i<=n;i++){in+=p[i];if(p[i])add(S,i,p[i],0);}
        for(i=1;i<=n;i++){out+=p[i+n];if(p[i+n])add(i+n,T,p[i+n],0);}
        for(i=1;i<=n;i++)add(col[i],col[i+n],1,-a[i]);
        mcmf();
    }
    
  • 相关阅读:
    Hard Rock
    Codeforces Round #416 (Div. 2) B. Vladik and Complicated Book
    codeforces 793B. Igor and his way to work
    codeforces 1B Spreadsheets
    HDU 1069 Monkey and Banana
    codeforces 2B The least round way
    【机器学习】 通俗说拟合
    python-八皇后问题
    python-核心知识思维导图
    python-@property 属性
  • 原文地址:https://www.cnblogs.com/VIrtu0s0/p/10043446.html
Copyright © 2011-2022 走看看