[NOI2009]植物大战僵尸
Description:
给你一个n*m的地图,每个位置上有一棵植物,要吃到一行中左边的必须先吃掉右边的
给定每个植物的分数,以及一些植物可以攻击到的位置(你不能经过这些位置)
问能获取到的最大分数是多少
Hint:
\(n,m \le 20\)
Solution:
发现我们要吃一个处在被攻击位置的植物,就要先吃掉那个攻击者
并且要吃左边必须先吃右边,这符合最大权闭合子图的定义,可以建图直接跑
但是有个问题,"保护"关系可能成环,于是要先拓扑排序判掉一些不可能吃到的点
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ls p<<1
#define rs p<<1|1
using namespace std;
typedef long long ll;
const int mxn=1e3+5,inf=1e9;
int n,m,S,T,cnt,cnt1,ans,sum,in[mxn],hd[mxn],hd1[mxn],dep[mxn],val[mxn],del[mxn],cur[mxn];
inline int read() {
char c=getchar(); int x=0,f=1;
while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
return x*f;
}
inline void chkmax(int &x,int y) {if(x<y) x=y;}
inline void chkmin(int &x,int y) {if(x>y) x=y;}
struct ed {
int to,nxt,w;
}t1[mxn<<1],t[mxn<<1];
inline void add1(int u,int v) {
t1[++cnt1]=(ed) {v,hd1[u]}; hd1[u]=cnt1; ++in[v];
}
inline void add2(int u,int v,int w) {
t[cnt]=(ed) {v,hd[u],w}; hd[u]=cnt++;
t[cnt]=(ed) {u,hd[v],0}; hd[v]=cnt++;
}
void Topsort() {
queue<int > q;
for(int i=1;i<=n*m;++i)
if(!in[i]) q.push(i);
else del[i]=1;
while(!q.empty()) {
int u=q.front(); q.pop(); del[u]=0;
for(int i=hd1[u];i;i=t1[i].nxt) {
int v=t1[i].to; --in[v];
if(!in[v]) q.push(v);
}
}
}
void init() {
cnt=0; S=0; T=n*m+1;
for(int i=1;i<=n*m;++i)
if(!del[i]) {
if(val[i]>0) {
sum+=val[i];
add2(S,i,val[i]);
}
else add2(i,T,-val[i]);
for(int j=hd1[i];j;j=t1[j].nxt) {
int v=t1[j].to;
if(!del[v]) add2(v,i,inf);
}
}
}
int bfs() {
memset(dep,0,sizeof(dep)); queue<int > q;
q.push(S); dep[S]=1;
for(int i=1;i<=n*m;++i) cur[i]=hd[i];
while(!q.empty()) {
int u=q.front(); q.pop();
for(int i=hd[u];i!=-1;i=t[i].nxt) {
int v=t[i].to;
if(dep[v]==0&&t[i].w>0)
dep[v]=dep[u]+1,q.push(v);
}
}
if(dep[T]==0) return 0;
return 1;
}
int dfs(int u,int f) {
if(u==T) return f;
for(int &i=cur[u];i!=-1;i=t[i].nxt) {
int v=t[i].to;
if(dep[v]==dep[u]+1&&t[i].w>0) {
int tp=dfs(v,min(f,t[i].w));
if(tp>0) {
t[i].w-=tp;
t[i^1].w+=tp;
return tp;
}
}
}
return 0;
}
void Dinic() {
while(bfs())
while(int tp=dfs(S,inf))
ans+=tp;
}
int main()
{
n=read(); m=read();
int a,b,w; memset(hd,-1,sizeof(hd));
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j) {
int x=(i-1)*m+j;
val[x]=read(); w=read();
while(w--) {
a=read(); b=read(); ++a,++b;
int y=(a-1)*m+b; add1(x,y);
}
}
for(int i=1;i<=n;++i)
for(int j=2;j<=m;++j) {
int x=(i-1)*m+j,y=x-1;
add1(x,y);
}
Topsort(); init(); Dinic();
printf("%d",sum-ans);
return 0;
}