Codeforces Round #523 (Div. 2) E. Politics(最小費+思維建圖)
阿新 • • 發佈:2018-11-30
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(); }