您的位置:首页 > 其它

[BZOJ 1565][NOI 2009]植物大战僵尸(Dinic最大流+拓扑排序)

2014-12-05 18:55 369 查看
题目链接: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;
}



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: