[图论记录]ARC107F Sum of Abs

command_block

2021-10-26 15:14:06

Personal

**题意** : 给一个无向图,点 $i$ 有 $a_i,b_i$ 两个权值。 可以花费 $a_i$ 的代价删掉 $i$ ,最终剩下来的各个连通块的 $\big|\sum b_i\big|$ 的和就是收益。 求 收益-代价 的最大值。 $n,m\leq 300$ ,时限$\texttt{2s}$。 ------------ 不太会从头推,直接给做法吧。 注意到绝对值可以看做正负抵消,具体地,记 $S^+=\sum_{i=1}^n[b_i>0]b_i,\ S^-=\sum_{i=1}^n[b_i<0]-b_i$ ,则有 $\big|\sum b_i\big|=\max(S^+,S^-)-\min(S^+,S^-)=S^++S^--2\min(S^+,S^-)$。 于是问题转化为最小化 $a+2\min(S^+,S^-)$ 的值。 考虑最小割,对于原图的边 $(u,v)$ ,连边 $u'\rightarrow v,\ v'\rightarrow u:+\infty$ 。 其中 $u'$ 是 $u$ 的“出点”。 对于点 $u$ ,若 $b_u<0$ 则连边 $u\rightarrow T: -2b_u$ ,否则连边 $S\rightarrow u: 2b_u$ 。 这样,对于一个联通块,要么全割正的 $b$ ,要么全割负的 $b$ ,最小割即为 $2\min(S^+,S^-)$ 。 接下来考虑 $a$ ,连边 $u\rightarrow u':a_u+|b_u|$ ,若将这条边割去,对连通性的影响等价于将 $u$ 点删去。这里要 $+b_u$ 因为删点会影响 $S^++S^-$ 。 跑个 Dinic 算最小割就好。 ```cpp #include<algorithm> #include<cstdio> #include<queue> #define MaxN 605 #define MaxM 3050 using namespace std; const int INF=1000000000; int S,T; struct Line{int nxt,t,cap;}l[MaxM]; int tl=1,fir[MaxN],dis[MaxN],cur[MaxN]; void adl(int f,int t,int cap){ l[++tl]=(Line){fir[f],t,cap};fir[f]=tl; l[++tl]=(Line){fir[t],f,0};fir[t]=tl; } bool bfs() { static queue<int> q; for (int i=1;i<=T;i++) {cur[i]=fir[i];dis[i]=0;} q.push(S);dis[S]=1; while(!q.empty()){ int u=q.front();q.pop(); for (int i=fir[u];i;i=l[i].nxt) if (l[i].cap&&!dis[l[i].t]){ dis[l[i].t]=dis[u]+1; q.push(l[i].t); } }return dis[T]; } int dfs(int u,int flow) { if (u==T)return flow; int sum=0; for (int &i=cur[u];i;i=l[i].nxt) if (l[i].cap&&dis[l[i].t]==dis[u]+1){ int sav=dfs(l[i].t,min(flow,l[i].cap)); if (sav){ l[i].cap-=sav;l[i^1].cap+=sav; sum+=sav;flow-=sav; if (!flow)break; }else dis[l[i].t]=-1; } return sum; } int n,m,a[MaxN]; int main() { scanf("%d%d",&n,&m); int ans=0;S=n+n+1;T=S+1; for (int u=1;u<=n;u++)scanf("%d",&a[u]); for (int u=1,b;u<=n;u++){ scanf("%d",&b); adl(u,u+n,a[u]+abs(b));ans+=abs(b); if (b>0)adl(S,u,2*b); if (b<0)adl(u+n,T,-2*b); } for (int i=1,u,v;i<=m;i++){ scanf("%d%d",&u,&v); adl(u+n,v,INF); adl(v+n,u,INF); } while(bfs())ans-=dfs(S,INF); printf("%d",ans); return 0; } ```