BZOJ 1565: [NOI2009]植物大战僵尸
1565: [NOI2009]植物大战僵尸
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 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
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\n",max(ans-dinic(),0)); 95 return 0; 96 }//Cap ou pas cap. Cap.
By NeighThorn