题意:
给出一片n*m的草坪,上面每个点有一个植物;
现在由你来从最右面放出一些僵尸来进攻这些植物;
僵尸到一个植物面前的时候就可以吃掉这个植物,并且得到这个植物的的得分(可正可负);
每个植物可以攻击几个位置,并且僵尸只能从右面出发,也就是说在吃掉右面的植物之前不可能吃掉左面的;
僵尸是无限的,求最大得分;
n<=20,m<=30;
题解:
原来这个就是最大权闭合子图啊。。似乎以前没刷过的样子= =
总之先建图:
将每个植物向能保护它的植物连流量为无穷的边;
从源点向正得分植物连流量为得分的边;
从负得分植物向汇点连流量为得分相反数的边;
最后用所有正权值的和减去最小割就是了;
这样建图解决最大权闭合子图问题是正确的,感性上讨论一下各种边就差不多理解的了吧;
然而通常的最大权闭合子图都是拓扑图,在这个问题中可以有环存在;
所以有些点是永远也不可能取到的,这些点我们不要,也就是拓扑排序之后排不到的点;
然后建图就是正确的了,跑最大权闭合子图即可;
代码:
#include<queue> #include<stdio.h> #include<string.h> #include<algorithm> #define N 40 #define E 400000 using namespace std; int next[E],to[E],flow[E],head[N*N],ce=1; int dis[N*N],S,T,sum; int val[N*N]; queue<int>q; void add(int x,int y,int fl) { to[++ce]=y; flow[ce]=fl; next[ce]=head[x]; head[x]=ce; to[++ce]=x; flow[ce]=0; next[ce]=head[y]; head[y]=ce; } bool BFS() { int x,i; memset(dis,0,sizeof(dis)); dis[S]=1; q.push(S); while(!q.empty()) { x=q.front(),q.pop(); for(i=head[x];i;i=next[i]) { if(flow[i]&&!dis[to[i]]) { dis[to[i]]=dis[x]+1; q.push(to[i]); } } } return dis[T]!=0; } int dfs(int x,int lim) { if(x==T) return lim; int ret=0,i,temp; for(i=head[x];i;i=next[i]) { if(flow[i]&&dis[to[i]]==dis[x]+1) { temp=dfs(to[i],min(flow[i],lim-ret)); ret+=temp; flow[i]-=temp,flow[i^1]+=temp; if(ret==lim) return ret; } } if(!ret) dis[x]=0; return ret; } namespace Graph { int next[E],to[E],head[N*N],ce; int in[N*N]; bool vis[N*N]; void add(int x,int y) { to[++ce]=y; next[ce]=head[x]; head[x]=ce; in[y]++; } void slove(int n,int m) { int i,x,tot=n*m; for(x=0;x<tot;x++) { if(!in[x]) q.push(x); } while(!q.empty()) { x=q.front(),q.pop(); vis[x]=1; for(i=head[x];i;i=next[i]) { in[to[i]]--; if(!in[to[i]]) q.push(to[i]); } } for(x=0;x<tot;x++) { if(!vis[x]) continue; if(val[x]>=0) ::add(S,x,val[x]),sum+=val[x]; else ::add(x,T,-val[x]); for(i=head[x];i;i=next[i]) { if(vis[to[i]]) ::add(to[i],x,0x3f3f3f3f); } } } } int main() { int n,m,w,i,j,k,x,y,ans; scanf("%d%d",&n,&m); S=n*m,T=S+1; for(i=0,sum=0;i<n;i++) { for(j=0;j<m;j++) { if(j) Graph::add(i*m+j,i*m+j-1); scanf("%d%d",&val[i*m+j],&w); for(k=1;k<=w;k++) { scanf("%d%d",&x,&y); Graph::add(i*m+j,x*m+y); } } } Graph::slove(n,m); ans=0; while(BFS()) ans+=dfs(S,0x3f3f3f3f); printf("%d\n",sum-ans); return 0; }