1. 程式人生 > >2018.10.10 bzoj1565: [NOI2009]植物大戰殭屍(最大權閉合子圖+拓撲排序)

2018.10.10 bzoj1565: [NOI2009]植物大戰殭屍(最大權閉合子圖+拓撲排序)

傳送門 由題可以得出一些關係。

  1. 如果對於同一行的相鄰兩個格子(i,j),(i,j+1)(i,j),(i,j+1),那麼前者是後者的後繼。
  2. 如果對於兩個格子A(a,b),B(c,d)A(a,b),B(c,d),如果AA保護BB,那麼BBAA的後繼。

然後可以發現如果以這樣的方式建圖會產生環。 並且由條件知整個環都不能選。 因此我們先在反向圖上拓撲排序去掉環。 然後就是最大權閉合子圖的裸板了。 程式碼:

#include<bits/stdc++.h>
#define N 500005
using namespace std;
inline
int read(){ int ans=0,w=1; char ch=getchar(); while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();} while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar(); return ans*w; } int n,m,val[N],du[N]; bool vis[N]; struct edge{int v,next,c;}; struct Dinic{ int first[N],cnt,cur[N],d[N],s,
t; edge e[N<<1]; inline void init(){memset(first,-1,sizeof(first)),s=0,cnt=-1,t=N-5;} inline void addedge(int u,int v,int c){e[++cnt].v=v,e[cnt].next=first[u],e[cnt].c=c,first[u]=cnt;} inline void add(int u,int v,int c){addedge(u,v,c),addedge(v,u,0);} inline bool bfs(){ queue<int>q;
memset(d,-1,sizeof(d)),d[s]=0,q.push(s); while(!q.empty()){ int x=q.front(); q.pop(); for(int i=first[x];~i;i=e[i].next){ int v=e[i].v; if(~d[v]||!e[i].c)continue; d[v]=d[x]+1,q.push(v); } } return ~d[t]; } inline int dfs(int x,int f){ if(!f||x==t)return f; int flow=f; for(int&i=cur[x];~i;i=e[i].next){ int v=e[i].v; if(!flow)break; if(e[i].c&&d[v]==d[x]+1){ int tmp=dfs(v,min(flow,e[i].c)); flow-=tmp,e[i].c-=tmp,e[i^1].c+=tmp; if(!tmp)d[v]=-1; } } return f-flow; } inline int solve(){ int ret=0; while(bfs())memcpy(cur,first,sizeof(first)),ret+=dfs(s,0x3f3f3f3f); return ret; } }dinic; inline int idx(int a,int b){return (a-1)*m+b;} vector<int>g[N],h[N]; inline void add(int u,int v){g[u].push_back(v),h[v].push_back(u),++du[v];} int main(){ n=read(),m=read(),dinic.init(); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j){ val[idx(i,j)]=read(); int k=read(); while(k--){ int x=read()+1,y=read()+1; add(idx(i,j),idx(x,y)); } if(j>=2)add(idx(i,j),idx(i,j-1)); } queue<int>q; for(int i=1;i<=n*m;++i)if(!du[i])q.push(i); while(!q.empty()){ int x=q.front(); q.pop(),vis[x]=1; for(int i=0;i<g[x].size();++i){ --du[g[x][i]]; if(!du[g[x][i]])q.push(g[x][i]); } } int ans=0; for(int i=1;i<=n*m;++i){ if(!vis[i])continue; if(val[i]>0)ans+=val[i],dinic.add(dinic.s,i,val[i]); else dinic.add(i,dinic.t,-val[i]); for(int j=0;j<h[i].size();++j)if(vis[h[i][j]])dinic.add(i,h[i][j],0x3f3f3f3f); } cout<<ans-dinic.solve(); return 0; }