【bzoj1565】[NOI2009]植物大战僵尸

1565: [NOI2009]植物大战僵尸

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 2164  Solved: 1001
[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 。

 

 

【题解】

这题的麻烦之处在于网络中可能出现环,导致死循环。

首先建图:如果一行之中,有一个植物被在同一行中左边的植物保护,就会形成环,那么我们只需要在每一行的植物向左边一个植物连一条边就行了。然后就是由保护者向被保护者连一条边。

拓扑判环、删点,不再赘述。

重新建图:遍历每个点,如果这个点没被删除,就在新图上保留有这个点出发的所有边。并判断:如果点权为正,从此点向终点连边,否则,由起点向此点连边。顺便记下所有正点权之和sum

求最大流ans后,sum-ans就是答案。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<cmath>
  6 #include<ctime>
  7 #include<algorithm>
  8 using namespace std;
  9 #define MAXN 610000
 10 #define INF 1000000000
 11 struct node{int y,next,v,rel;}E[MAXN],e[MAXN];
 12 int n,m,len,S,T,ans,sum,v[MAXN],Link1[MAXN],id[MAXN],q[MAXN],del[MAXN],Link[MAXN],level[MAXN];
 13 inline int read()
 14 {
 15     int x=0,f=1;  char ch=getchar();
 16     while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getchar();}
 17     while(isdigit(ch))  {x=x*10+ch-'0';  ch=getchar();}
 18     return x*f;
 19 }
 20 void insert1(int x,int y)  {id[y]++;E[++len].next=Link1[x];Link1[x]=len;E[len].y=y;}
 21 void insert2(int x,int y,int v)  
 22 {
 23     e[++len].next=Link[x];Link[x]=len;e[len].y=y;e[len].v=v;e[len].rel=len+1;
 24     e[++len].next=Link[y];Link[y]=len;e[len].y=x;e[len].v=0;e[len].rel=len-1;
 25 }
 26 void dfs(int x)
 27 {
 28     del[x]=1;
 29     for(int i=Link1[x];i;i=E[i].next)
 30         if(!del[E[i].y])  dfs(E[i].y);
 31 }
 32 void topsort()
 33 {
 34     int head=0,tail=0;
 35     for(int i=1;i<=n*m;i++)  if(!id[i])  q[++tail]=i;  else del[i]=1;
 36     while(++head<=tail)
 37     {
 38         int now=q[head];
 39         del[now]=0;
 40         for(int i=Link1[now];i;i=E[i].next)
 41         {
 42             id[E[i].y]--;
 43             if(!id[E[i].y])  q[++tail]=E[i].y;
 44         }
 45     }
 46     for(int i=1;i<=n*m;i++)  if(del[i])  dfs(i);
 47 }     
 48 void build()
 49 {
 50     len=0;  S=0;  T=n*m+1;
 51     for(int i=1;i<=n*m;i++)
 52         if(!del[i])
 53         {
 54             if(v[i]>0) {sum+=v[i]; insert2(i,T,v[i]);}
 55             else insert2(S,i,-v[i]);
 56             for(int j=Link1[i];j;j=E[j].next)
 57                 if(!del[E[j].y])
 58                     insert2(i,E[j].y,INF);
 59         }
 60 }
 61 bool bfs()
 62 {
 63     memset(level,-1,sizeof(level));
 64     int head=0,tail=1;
 65     q[1]=S;  level[S]=0;
 66     while(++head<=tail)
 67     {
 68         for(int i=Link[q[head]];i;i=e[i].next)
 69             if(e[i].v&&level[e[i].y]<0)
 70             {
 71                 q[++tail]=e[i].y;
 72                 level[q[tail]]=level[q[head]]+1;
 73             }
 74     }
 75     return level[T]>=0;
 76 }
 77 int MAXFLOW(int x,int flow)
 78 {
 79     if(x==T)  return flow;
 80     int d=0,maxflow=0;
 81     for(int i=Link[x];i&&maxflow<flow;i=e[i].next)
 82         if(level[e[i].y]==level[x]+1&&e[i].v)
 83             if(d=MAXFLOW(e[i].y,min(e[i].v,flow-maxflow)))
 84             {
 85                 maxflow+=d;
 86                 e[i].v-=d;
 87                 e[e[i].rel].v+=d;
 88             }
 89     if(!maxflow)  level[x]=-1;
 90     return maxflow;
 91 }
 92 void solve()
 93 {
 94     int d=0;
 95     while(bfs())
 96         while(d=MAXFLOW(S,INF))
 97             ans+=d;
 98 }
 99 int main()
100 {
101     //freopen("pvz.in","r",stdin);
102     //freopen("pvz.out","w",stdout);
103     n=read();  m=read();
104     for(int i=1;i<=n;i++)
105         for(int j=1;j<=m;j++)
106         {
107             int x=(i-1)*m+j;
108             v[x]=read();  int w=read();
109             while(w--)
110             {
111                 int a=read(),b=read();
112                 a++;  b++;
113                 int y=(a-1)*m+b;
114                 insert1(x,y);
115             }
116         }
117     for(int i=1;i<=n;i++)
118         for(int j=2;j<=m;j++)
119         {
120             int x=(i-1)*m+j,y=x-1;
121             insert1(x,y);
122         }
123     topsort();
124     build();
125     solve();
126     printf("%d\n",sum-ans);
127     return 0;
128 }

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值