您的位置:首页 > 理论基础 > 计算机网络

bzoj-1565 植物大战僵尸

2015-11-24 15:37 645 查看
题意:

给出一片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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息