您的位置:首页 > 理论基础 > 计算机网络

Bzoj1565:[NOI2009]植物大战僵尸:拓扑排序+网络流

2016-07-17 09:37 525 查看
题目链接:1565:[NOI2009]植物大战僵尸

显然的最大权闭合图模型,但是裸上是错的

每个植物相他所攻击的位置连边,如果形成一个环那么这个换必然无解

进一步,这个环所保护的点都不能取到

所以我们拓扑排序求出可以干掉的植物集合再做网络流即可

#include<queue>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1000010;
const int inf=0x7fffffff/3;
int n,m,tot=1,h[maxn],In[maxn],S,T;
struct edge{int to,next,w;}G[maxn];
int cur[maxn],vis[maxn],val[maxn],ans=0;
bool flag[maxn];

void add(int x,int y,int z){
In[x]++;
G[++tot].to=y;G[tot].next=h[x];h[x]=tot;G[tot].w=z;
G[++tot].to=x;G[tot].next=h[y];h[y]=tot;G[tot].w=0;
}

void toposort(){
queue<int>q;
for (int i=S;i<=T;++i) if (!In[i]) q.push(i);
while (!q.empty()){
int u=q.front(); q.pop(); flag[u]=1;
if (val[u]>0) ans+=val[u];
for (int i=h[u];i;i=G[i].next){
int v=G[i].to;
if (!G[i].w){
In[v]--;
if (!In[v]) q.push(v);
}

}
}
}

bool bfs(){
for (int i=S;i<=T;++i) vis[i]=-1;
queue<int>q; q.push(S); vis[S]=0;
while (!q.empty()){
int u=q.front(); q.pop();
for (int i=h[u];i;i=G[i].next){
int v=G[i].to;
if (vis[v]==-1&&G[i].w>0&&flag[v]){
vis[v]=vis[u]+1;
q.push(v);
}
}
}return vis[T]!=-1;
}

int dfs(int x,int f){
if (x==T||!f) return f;
int used=0,w;
for (int i=cur[x];i;i=G[i].next)
if (vis[G[i].to]==vis[x]+1){
w=f-used;
w=dfs(G[i].to,min(G[i].w,w));
G[i].w-=w; G[i^1].w+=w;
used+=w; if (G[i].w) cur[x]=i;
if (used==f) return used;
}
if (!used) vis[x]=-1;
return used;
}

int dinic(){
int ret=0;
while (bfs()){
for (int i=S;i<=T;++i) cur[i]=h[i];
ret+=dfs(S,inf);
}return ret;
}

int main(){
scanf("%d%d",&n,&m);
S=0; T=n*m+1;
for (int i=1;i<=n*m;++i){
scanf("%d",&val[i]);
if (val[i]>0) add(S,i,val[i]);
else add(i,T,-val[i]);
int a,b,c;
scanf("%d",&a);
for (int j=1;j<=a;++j){
scanf("%d%d",&b,&c);
add(b*m+c+1,i,inf);
}
if (i%m!=0) add(i,i+1,inf);//选了左侧必须先选右侧
}
toposort();
printf("%d",ans-dinic());
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息