最小割:最大权闭合子图
最小割:最大权闭合子图
最大权闭合子图
给一个 DAG,你要选一个子图,如果一个点被选则要求它的所有后继节点都必须选,求可选的合法子图的最大权。
最小割模型
我们这样建模:
- 对于边 \(u\to v\),连一条 \(u\to v\) 的容量为 \(\inf\) 的边。
- 对于 \(val_x\ge 0\),连一条 \(S\to x\) 的容量为 \(val_x\) 的边。
- 对于 \(val_x< 0\),连一条 \(x\to T\) 的容量为 \(-val_x\) 的边。
最后的答案是:所有正权和 减去 最小割。
正确性可以这样考虑:
我们把割完后与 \(S\) 连通的点看做选入闭合子图,否则与 \(T\) 相连通即不选入。
那么对于一个正权点,发现其与 \(S\) 连通后,其后继的所有负权点都会与 \(T\) 相割。 这里满足了「闭合」。
那么那些与 \(S\) 相割的正权点就是不选入子图,在最小割中减去了,而与 \(T\) 相割的负权点就有负的贡献,也在最小割中减去了。这里说明了最终答案的「合法性」。
而根据贪心,一个选择的正权点的后继的正权点一定会被选,而一个负权点的前驱一定会选一个正权点。这里说明了最小割跑出的答案的「最优性」。
例题:P2805 [NOI2009] 植物大战僵尸
题意:选择一些点,点与点之间可能有依赖关系,要求前驱选完了其才可选,问选择的最大权。
解法
建图后我们先跑拓扑排序,把环上的点与环可达的点排除,因为这些点一定不可选。那么剩下的点之间一定是一张 DAG,这就是最大权闭合子图,我们按上述方法建图后跑网络流即可。
AC 代码:
const int D=1000,B=3e6;
const int inf=0x3f3f3f3f;
int to[B],nx[B],rl[B],st[D],cur[D],d[D],tot=1,S,T;
void _add(int x,int y,int z) {
to[++tot]=y,nx[tot]=st[x],st[x]=tot,rl[tot]=z;
}
void add(int x,int y,int z) {
_add(x,y,z),_add(y,x,0);
}
int go_on() {
memset(d,0,sizeof d);
d[S]=1;
queue<int> q;
q.push(S);
while(Size(q)) {
int u=q.front(); q.pop();
for(int i=st[u];i;i=nx[i]) {
int v=to[i];
if(!d[v]&&rl[i]) d[v]=d[u]+1,q.push(v);
}
}
return d[T]!=0;
}
int dfs(int x,int f) {
if(x==T) return f;
int res=f;
for(int &i=cur[x];i;i=nx[i]) {
int v=to[i];
if(d[v]==d[x]+1&&rl[i]) {
int t=dfs(v,min(res,rl[i]));
rl[i]-=t,rl[i^1]+=t,res-=t;
if(!res) return f;
}
}
if(res==f) d[x]=-1;
return f-res;
}
int dinic() {
int res=0;
while(go_on()) {
memcpy(cur,st,sizeof cur);
res+=dfs(S,inf);
}
return res;
}
const int N=D;
#define g(x,y) (x*m+y)
int n,m,sum=0;
int co[N],deg[N],bz[N];
vi t[N];
signed main(){
read(n,m);
S=n*m,T=S+1;
fu(i,0,n*m) {
read(co[i]);
int w; read(w);
while(w--) {
int x,y; read(x,y);
t[i].pb(g(x,y));
add(g(x,y),i,inf);
deg[g(x,y)]++;
}
}
fu(i,0,n) fu(j,0,m-1) {
t[g(i,j+1)].pb(g(i,j)),deg[g(i,j)]++;
add(g(i,j),g(i,j+1),inf);
}
queue<int> q;
fu(i,0,n*m) if(!deg[i]) q.push(i);
while(Size(q)) {
int u=q.front(); q.pop();
bz[u]=1;
for(int v:t[u]) {
deg[v]--;
if(!deg[v]) q.push(v);
}
}
fu(i,0,n*m) if(bz[i]) {
if(co[i]>=0) sum+=co[i],add(S,i,co[i]);
else add(i,T,-co[i]);
}
write(sum-dinic());
return 0;
}

浙公网安备 33010602011771号