BZOJ 1565 NOI2009 植物大战僵尸

1565: [NOI2009]植物大战僵尸

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 2922  Solved: 1332
[Submit][Status][Discuss]

Description

Input

Output

仅包含一个整数,表示可以获得的最大能源收入。注意,你也可以选择不进行任何攻击,这样能源收入为0。

Sample Input

3 2
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;
}

  

 

posted @ 2017-12-04 15:33  zhangenming  阅读(187)  评论(0编辑  收藏  举报