【NOI2009-DAY2-T1】【BZOJ1565】—植物大战僵尸(最大权闭合子图+拓扑排序)
估计是当天签到题
考虑到如果一株植物被另一株植物给保护着,那就必须要先吃掉植物才可以吃掉,
那考虑我们将所有被保护的植物向保护其的植物连一条边,表示要吃掉保护它的植物
那么我们现在就相当于是在找图的一个权闭合子图了(如果不会或是不知道的权闭合子图的自行百度吧)
从源点向所有贡献为正的点连一条边权为点权的边,所有贡献为负的点向汇点连一条边权为点权绝对值的边
这样跑出来的最大流=最小割=最大权闭合子图
但注意到有可能保护关系形成了一个环,这时候显然是不可能攻击环上植物的
先拓扑排序排除一下环就是了
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();
int res=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return res*f;
}
const int N=805;
const int M=1000005;
const int inf=19260817;
int n,m,cnt=1,adj[N],nxt[M<<1],to[M<<1],cap[M<<1],val[N],in[N],lev[N],vis[N],tp[N],str,des,ans;
inline int pos(int x,int y){
return (y-1)*m+x;
}
inline void addedge(int u,int v,int w){
nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,cap[cnt]=w;
nxt[++cnt]=adj[v],adj[v]=cnt,to[cnt]=u,cap[cnt]=0;
}
inline void topsort(){
queue<int> q;
for(int i=1;i<=n*m;i++){
if(!in[i])q.push(i);
}
while(!q.empty()){
int u=q.front();q.pop();vis[u]=1;
for(int e=adj[u];e;e=nxt[e]){
int v=to[e];
in[v]--;
if(!in[v])q.push(v);
}
}
}
inline bool bfs(){
memset(lev,-1,sizeof(lev));
queue<int> q;
q.push(str),lev[str]=0;
while(!q.empty()){
int u=q.front();q.pop();
for(int e=adj[u];e;e=nxt[e]){
int v=to[e];
if(cap[e]>0&&vis[v]&&lev[v]==-1){
lev[v]=lev[u]+1;
q.push(v);
if(v==des)return true;
}
}
}
return false;
}
int dinic(int u,int flow){
if(u==des)return flow;
int res=0;
for(int &e=tp[u];e;e=nxt[e]){
int v=to[e];
if(cap[e]>0&&vis[v]&&lev[v]==lev[u]+1){
int mn=dinic(v,min(flow-res,cap[e]));
res+=mn,cap[e]-=mn,cap[e^1]+=mn;
}
}
return res;
}
inline int solve(){
int res=0;
while(bfs()){
memcpy(tp,adj,sizeof(adj));
res+=dinic(str,inf);
}
return res;
}
int main(){
n=read(),m=read();str=n*m+1,des=str+1;
for(int i=1;i<=m*n;i++){
val[i]=read();
int w=read();
for(int j=1;j<=w;j++){
int y=read()+1,x=read()+1;
addedge(pos(x,y),i,inf);in[pos(x,y)]++;
}
if(i%m){
addedge(i,i+1,inf);in[i]++;
}
}
topsort();
vis[str]=vis[des]=1;
for(int i=1;i<=n*m;i++){
if(!vis[i])continue;
if(val[i]>0)addedge(str,i,val[i]),ans+=val[i];
if(val[i]<0)addedge(i,des,-val[i]);
}
cout<<(ans-solve())<<'\n';
}