2018.10.10 bzoj1565: [NOI2009]植物大戰殭屍(最大權閉合子圖+拓撲排序)
阿新 • • 發佈:2018-12-14
傳送門 由題可以得出一些關係。
- 如果對於同一行的相鄰兩個格子,那麼前者是後者的後繼。
- 如果對於兩個格子,如果保護,那麼是的後繼。
然後可以發現如果以這樣的方式建圖會產生環。 並且由條件知整個環都不能選。 因此我們先在反向圖上拓撲排序去掉環。 然後就是最大權閉合子圖的裸板了。 程式碼:
#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;
}