题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1565
orz题目太神。。。膝盖已经跪烂。。。。
这题需要我们建立起植物和植物之间复杂的保护关系,以及吃植物得到的损失和回报,因此要用最大流搞,建模太神奇了,跪跪跪。。。
首先我们建立源点和汇点,对于每个植物,如果吃它可以得到能源,在源点和它之间连一条边,容量为得到的能源数量。如果吃它要消耗能源,则在它和汇点之间建立一条边,边权为消耗的能源个数。
然后对于每个植物,将它和它的保护区域中的每个植物分别连一条边,容量为无穷大。
然后要注意,每一行的最后一个点要和下一行的第一个点连一条边,容量为无穷大,这样才能保证做好的图是联通的。
考虑到有可能有一些植物们可以相互保护,这样的话僵尸是吃不了它们的,这种情况下在图中这些植物会连成一个环,因此接着要拓扑排序,把图中所有的环都消去。
最后Dinic跑最大流,答案=图上所有不属于环的植物的权值-最大流
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> #include <queue> #define MAXE 500500 #define MAXV 650 #define INF 0x3f3f3f3f using namespace std; int ans=0,f[MAXV],S,T,n,m; bool used[MAXV]; //used[i]=true表明点i没有被去除掉 int inDegree[MAXV]; //每个点的入度 //Start Of Graph Structure struct edge { int u,v,cap,next; }edges[MAXE]; int head[MAXV],nCount=-1; void AddEdge(int U,int V,int C) { edges[++nCount].u=U; edges[nCount].v=V; edges[nCount].cap=C; edges[nCount].next=head[U]; head[U]=nCount; } void add(int U,int V,int C) { AddEdge(U,V,C); AddEdge(V,U,0); inDegree[U]++; } //End Of Graph Structure //Start Of Topological Sort void TopoSort() { queue<int>q; while(!q.empty()) q.pop(); for(int i=S;i<=T;i++) if(!inDegree[i]) q.push(i); while(!q.empty()) { int u=q.front(); q.pop(); used[u]=true; if(f[u]>0) ans+=f[u]; for(int p=head[u];p!=-1;p=edges[p].next) { int v=edges[p].v; if(p&1) { inDegree[v]--; if(!inDegree[v]) q.push(v); } } } } //End Of Topological Sort //Start Of Dinic Max-flow Algorithm int layer[MAXV]; //bfs分出的层 bool CountLayer() { memset(layer,0,sizeof(layer)); queue<int>q; while(!q.empty()) q.pop(); q.push(S); layer[S]=1; while(!q.empty()) { int u=q.front(); q.pop(); for(int p=head[u];p!=-1;p=edges[p].next) { int v=edges[p].v; if(!layer[v]&&edges[p].cap&&used[v]) { layer[v]=layer[u]+1; q.push(v); if(v==T) return true; } } } return false; } int DFS(int u,int flow) { int tmp=flow; if(u==T) return flow; for(int p=head[u];p!=-1;p=edges[p].next) { int v=edges[p].v; if(edges[p].cap&&layer[v]==layer[u]+1&&tmp) { int now=DFS(v,min(tmp,edges[p].cap)); if(!now) layer[v]=0; tmp-=now; edges[p].cap-=now; edges[p^1].cap+=now; } } return flow-tmp; } int Dinic() { int maxflow=0; while(CountLayer()) maxflow+=DFS(S,INF); return maxflow; } //End Of Dinic Max-flow Algorithm int main() { memset(head,-1,sizeof(head)); int x,y,r,c; scanf("%d%d",&m,&n); S=0,T=n*m+1; for(int i=1;i<=m*n;i++) { scanf("%d",&f[i]); if(f[i]>0) //吃该植物能得到能量 add(S,i,f[i]); else //吃该植物要付出能量 add(i,T,-f[i]); scanf("%d",&y); //攻击范围 for(int j=1;j<=y;j++) { scanf("%d%d",&r,&c); add(r*n+c+1,i,INF); //从被保护的植物到该植物连一条容量无穷大的边 } if(i%n) add(i,i+1,INF); } TopoSort(); cout << ans-Dinic() << endl; return 0; }