BZOJ1565: [NOI2009]植物大战僵尸

来源:互联网 发布:矩阵论第二版答案徐仲 编辑:程序博客网 时间:2024/05/02 00:18

题目链接

【题目大意】

给定n*m大小的地图,每块有一种植物,每种植物两个功能:
①:吃掉该植物可获得x点收益,可正可负;
②:可保护若干块地上的植物。
任何一个点的植物存活时,它左侧的所有植物都无法被攻击。
求最大获利值。

【分析】

由题意易知,想获得某点的植物的收益,可能有先决条件并且该条件必须满足,即为最大权闭合图。
但此题有特殊的情况:环。当出现环时,环上任意一点都不可取。
所以就要去环。
如何去环呢!??发现我们只需要标记可选取的点就可以了,而且建图时也是有向边,所以用拓扑排序~
但是做拓扑时又有一个问题,建边时是从被保护点–>保护点,但做拓扑显然需要反过来做。这个也好解决,网络流建边时偶数边为正向边,奇数边为反向边,沿反向边更新就好了。
接下来可以选择重新建图,也可以直接在BFS中加限制条件。(我比较懒,所以写的加限制条件。)

【代码】

#include <cstdio>#include <iostream>#include <queue>#include <vector>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#define N 605#define M 723605#define INF 1000000001using namespace std;typedef long long ll;typedef pair<ll,ll> pa;int read(){    int x=0,f=1;char ch=getchar();    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}    return x*f;}int n,m,cnt=1,S,T,ans;int b[M],p[N],nextedge[M],w[M],cur[N];int Level[N],a[N],in[N];bool Not_Pro[N];void Add(int x,int y,int z){    cnt++;    b[cnt]=y;    nextedge[cnt]=p[x];    p[x]=cnt;    w[cnt]=z;}void Anode(int x,int y,int z){    Add(x,y,z);Add(y,x,0);in[x]++;}void Input_Init(){    n=read();m=read();T=n*m+1;     for(int i=1;i<=n*m;i++)    {        static int x,y,xx,yy;        a[i]=x=read();        if(x>0) Anode(0,i,x);        else Anode(i,T,-x);        y=read();        while(y--)        {            xx=read(),yy=read();            Anode(xx*m+yy+1,i,INF);        }        if(i%m) Anode(i,i+1,INF);    }}void Top_Sort(){    queue<int>q;    for(int i=1;i<=T;i++) if(!in[i]) q.push(i);    while(!q.empty())    {        int k=q.front();q.pop();        Not_Pro[k]=1;if(a[k]>0) ans+=a[k];         for(int i=p[k];i;i=nextedge[i]) if(i&1)        {            int v=b[i];in[v]--;            if(!in[v]) q.push(v);        }    }}bool Bfs(){    queue<int>q;    q.push(S);    for(int i=0;i<=T;i++) Level[i]=0;    Level[S]=1;    while(!q.empty())    {        int k=q.front();q.pop();        for(int i=p[k];i;i=nextedge[i])        {            int v=b[i],f=w[i];            if(!Level[v]&&f&&Not_Pro[v])            {                Level[v]=Level[k]+1;                q.push(v);            }        }    }    return Level[T];}int Dfs(int x,int maxf){    if(x==T||!maxf) return maxf;    int rtn=0;    for(int i=cur[x];i&&maxf>rtn;i=nextedge[i])    {        int v=b[i],f=w[i];        if(Level[v]==Level[x]+1&&f)        {            f=Dfs(v,min(maxf-rtn,f));            w[i]-=f;w[i^1]+=f;            if(w[i]>0) cur[x]=i;            rtn+=f;        }    }    if(!rtn) Level[x]=0;    return rtn;}void Dinic(){    while(Bfs())    {        for(int i=0;i<=T;i++) cur[i]=p[i];        ans-=Dfs(S,INF);    }    printf("%d\n",ans);}int main(){    Input_Init();    Top_Sort();    Dinic();    return 0;}
0 0