BZOJ 1565: [NOI2009]植物大战僵尸

1565: [NOI2009]植物大战僵尸

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 2317  Solved: 1071
[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

分析:

看到这题就觉得亲切,这不是最大权闭合子图么...被保护的点向保护它的点连边,然后就是裸的最大权闭合子图...

但是发现过不了样例...TAT...因为有环...

所以我们要要删掉环的点,并且如果环上的点不能选,那么指向它的点也不能选...怎么办?拓扑排序?

但是拓扑排序只能判断有没有环,不能判断点是否在环上...比如下面这张图...

但是很巧的是我们的图是所有指向环的点都不能选...所以反向所有边...拓扑排序无法访问到的点就是需要删掉的点...(WA了好久QAQ...感谢LMY...)

代码:

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<queue>
 6 //by NeighThorn
 7 #define inf 0x7fffffff
 8 using namespace std;
 9   
10 const int maxn=700+5,maxm=2000000+5;
11   
12 int n,m,S,T,cnt,ans,hd[maxn],fl[maxm],in[maxn],to[maxm],nxt[maxm],pos[maxn],val[maxn],vis[maxn],mp[maxn][maxn];
13   
14 inline bool bfs(void){
15     memset(pos,-1,sizeof(pos));
16     int head=0,tail=0,q[maxn];
17     q[0]=S,pos[S]=0;
18     while(head<=tail){
19         int top=q[head++];
20         for(int i=hd[top];i!=-1;i=nxt[i])
21             if(pos[to[i]]==-1&&fl[i])
22                 pos[to[i]]=pos[top]+1,q[++tail]=to[i];
23     }
24     return pos[T]!=-1;
25 }
26   
27 inline int find(int v,int f){
28     if(v==T)
29         return f;
30     int res=0,t;
31     for(int i=hd[v];i!=-1&&f>res;i=nxt[i])
32         if(pos[to[i]]==pos[v]+1&&fl[i])
33             t=find(to[i],min(fl[i],f-res)),fl[i]-=t,fl[i^1]+=t,res+=t;
34     if(!res)
35         pos[v]=-1;
36     return res;
37 }
38   
39 inline int dinic(void){
40     int res=0,t;
41     while(bfs())
42         while(t=find(S,inf))
43             res+=t;
44     return res;
45 }
46   
47 inline void topo(void){
48     queue<int> q;
49     for(int i=1;i<=n*m;i++)
50         if(!in[i])
51             q.push(i),vis[i]=1;
52     while(!q.empty()){
53         int top=q.front();q.pop();
54         for(int i=1;i<=n*m;i++)
55             if(mp[top][i]){
56                 in[i]-=mp[top][i];
57                 if(!in[i])
58                     q.push(i),vis[i]=1;
59             }
60     }
61 }
62   
63 inline void add(int s,int x,int y){
64     fl[cnt]=s;to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
65     fl[cnt]=0;to[cnt]=x;nxt[cnt]=hd[y];hd[y]=cnt++;
66 }
67   
68 signed main(void){
69     // freopen("in.txt","r",stdin);
70     // freopen("out.txt","w",stdout);
71     memset(in,0,sizeof(in));
72     memset(hd,-1,sizeof(hd));
73     scanf("%d%d",&n,&m);T=n*m+1;
74     for(int i=1,s;i<=n*m;i++){
75         scanf("%d%d",&val[i],&s);
76         for(int j=1,x,y;j<=s;j++){
77             scanf("%d%d",&x,&y),x++,y++;
78             in[(x-1)*m+y]++;mp[i][(x-1)*m+y]++;
79         }
80         if(i%m)
81             in[i]++,mp[i+1][i]++;
82     }
83     topo();
84     for(int i=1;i<=n*m;i++)
85         if(vis[i]){
86             if(val[i]>0)
87                 ans+=val[i],add(val[i],S,i);
88             else
89                 add(-val[i],i,T);
90             for(int j=1;j<=n*m;j++)
91                 if(vis[j]&&mp[i][j])
92                     add(inf,j,i);
93         }
94     printf("%d
",max(ans-dinic(),0));
95     return 0;   
96 }//Cap ou pas cap. Cap.

By NeighThorn

原文地址:https://www.cnblogs.com/neighthorn/p/6259621.html