【bzoj1565】[NOI2009]植物大战僵尸
1565: [NOI2009]植物大战僵尸
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 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
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 }