1565: [NOI2009]植物大战僵尸
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 2922 Solved: 1332
[Submit][Status][Discuss]
Description
![](http://www.lydsy.com/JudgeOnline/images/1565_1.jpg)
Input
![](http://www.lydsy.com/JudgeOnline/images/1565_2.jpg)
Output
仅包含一个整数,表示可以获得的最大能源收入。注意,你也可以选择不进行任何攻击,这样能源收入为0。
Sample Input
3 2
10 0
20 0
-10 0
-5 1 0 0
100 1 2 1
100 0
10 0
20 0
-10 0
-5 1 0 0
100 1 2 1
100 0
Sample Output
25
HINT
在样例中, 植物P1,1可以攻击位置(0,0), P2, 0可以攻击位置(2,1)。
一个方案为,首先进攻P1,1, P0,1,此时可以攻击P0,0 。共得到能源收益为(-5)+20+10 = 25。注意, 位置(2,1)被植物P2,0保护,所以无法攻击第2行中的任何植物。
【大致数据规模】
约20%的数据满足1 ≤ N, M ≤ 5;
约40%的数据满足1 ≤ N, M ≤ 10;
约100%的数据满足1 ≤ N ≤ 20,1 ≤ M ≤ 30,-10000 ≤ Score ≤ 10000 。
Source
这道题是对最大闭合子图的应用
环上的点肯定是不能吃的,我们用topsort进行去环,求出答案即可
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
using namespace std;
inline int read()
{
int x=0;int f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
struct node
{
int y;
int next;
int back;
int flow;
}e[200100],ee[200100];
int linkk[200010];
int linkkk[200000];
int id[100010];
int f[100010];
int summ=0;
int q[100101];
int flag[100010]={};
int n,m,head,tail,len,st,end;
int getpoint(int x,int y)
{
return x*m-m+y;
}
void insert1(int xx,int yy)
{
ee[++len].y=yy;
ee[len].next=linkkk[xx];
linkkk[xx]=len;
ee[len].flow=4728479;
}
void insert(int xx,int yy,int vv)
{
e[++len].y=yy;
e[len].flow=vv;
e[len].next=linkk[xx];
e[len].back=len+1;
linkk[xx]=len;
e[++len].y=xx;
e[len].next=linkk[yy];
e[len].flow=0;
e[len].back=len-1;
linkk[yy]=len;
}
void topsort()//去环
{
tail=0;
head=0;
for(int i=1;i<=n*m;i++)
{
if(!id[i]) q[++tail]=i,flag[i]=1;
}
while(head<tail)
{
int tn=q[++head];
for(int i=linkkk[tn];i;i=ee[i].next)
{
id[ee[i].y]--;
if(!id[ee[i].y])
{
q[++tail]=ee[i].y;
flag[ee[i].y]=1;
}
}
}
}
void buildtu()
{
len=0;
for(int i=1;i<=n*m;i++)
{
if(flag[i]==0) continue;
if(f[i]>0) insert(st,i,f[i]),summ+=f[i];
if(f[i]<0) insert(i,end,-f[i]);
for(int j=linkkk[i];j;j=ee[j].next)
{
if(flag[ee[j].y]==0) continue;
insert(ee[j].y,i,624726488);
}
}
}
int level[10100];
bool vis[10010];
int getlevel()
{
memset(level,-1,sizeof(level));
memset(q,0,sizeof(q));
tail=head=0;
level[st]=0;
q[++tail]=st;
while(head<tail)
{
int tn=q[++head];
for(int i=linkk[tn];i;i=e[i].next)
{
if(level[e[i].y]==-1&&e[i].flow!=0)
{
q[++tail]=e[i].y;
level[e[i].y]=level[tn]+1;
}
}
}
return level[end]>-1;
}
int getmaxflow(int stt,int flow)
{
int maxflow=0;
int d=0;
if(stt==end) return flow;
for(int i=linkk[stt];i&&maxflow<flow;i=e[i].next)
{
if(level[e[i].y]==level[stt]+1&&e[i].flow)
{
if(d=getmaxflow(e[i].y,min(flow-maxflow,e[i].flow)))
{
maxflow+=d;
e[i].flow-=d;
e[e[i].back].flow+=d;
}
}
}
if(!maxflow) level[stt]=-1;
return maxflow;
}
void dinic()
{
int ans=0;
int sum;
while(getlevel())
{
while(sum=getmaxflow(st,31763786)) ans+=sum;
}
cout<<summ-ans<<endl;
}
int main()
{
cin>>n>>m;
st=0;
end=n*m+1;
for(int i=1;i<=n*m;i++)
{
f[i]=read();
int w;
cin>>w;
int now;
int a,b;
while(w--)
{
a=read()+1;
b=read()+1;
now=getpoint(a,b);
insert1(i,now);
id[now]++;
}
if(i%m==0) continue;
insert1(i+1,i);id[i]++;
}
topsort();
buildtu();
dinic();
return 0;
}