[BZOJ]1565: [NOI2009]植物大战僵尸 Tarjan+最小割(最大权闭合子图)

来源:互联网 发布:周哥k101淘宝店 编辑:程序博客网 时间:2024/05/06 06:01

Description
这里写图片描述

题解:

经典的最大权闭合子图模型,不会的可以去网上查找相关资料,挺简单的。这道题呢,对于植物i可以保护植物j,我们可以建一条j->i的有向边(注意同一行相邻2个植物也有保护关系),然后跑一次Tarjan,因为在一个环中的植物我们是不能选到的,对于这些不能选到的植物,我的处理方法是将他们的权值看做负无穷,然后其他的按照最大权闭合子图搞就行了。

代码:

#include<cstdio>#include<cstring>#include<queue>#include<iostream>#include<algorithm>using namespace std;const int inf=2147483647;const int Maxn=35;const int Max=910;struct Edge1{int y,next;}E[400000];struct Edge2{int y,d,next;}e[2110000];int score1[Maxn][Maxn],score2[Max],num[Maxn][Maxn],z=0;int n,m;int last[Max],len=1;int Last[Max],Len=0;int dfn[Max],low[Max],id=0,bel[Max],cnt=0,sta[Max],top=0,p[Max];bool in[Max],vis[Max],hh[Max][Max];void ins(int x,int y,int d){    int t=++len;    e[t].y=y;e[t].d=d;    e[t].next=last[x];last[x]=t;}void addedge(int x,int y,int d){ins(x,y,d);ins(y,x,0);}void Ins(int x,int y){    int t=++Len;    E[t].y=y;E[t].next=Last[x];Last[x]=t;}void Tarjan(int x){    low[x]=dfn[x]=++id;    sta[++top]=x;in[x]=true;    for(int i=Last[x];i;i=E[i].next)    {        int y=E[i].y;        if(!dfn[y])Tarjan(y),low[x]=min(low[x],low[y]);        else if(in[y])low[x]=min(low[x],dfn[y]);    }    if(low[x]==dfn[x])    {        int i;cnt++;        do        {            i=sta[top--];            bel[i]=cnt;            p[cnt]++;            in[i]=false;        }while(i!=x);    }}queue<int>q;int h[Max],st,ed;bool bfs(){    memset(h,0,sizeof(h));h[st]=1;    q.push(st);    while(!q.empty())    {        int x=q.front();q.pop();        for(int i=last[x];i;i=e[i].next)        if(e[i].d&&!h[e[i].y])h[e[i].y]=h[x]+1,q.push(e[i].y);    }    return h[ed];}int dfs(int x,int f){    if(x==ed)return f;    int s=0,t;    for(int i=last[x];i;i=e[i].next)    {        int y=e[i].y;        if(h[y]==h[x]+1&&e[i].d&&s<f)        {            t=dfs(y,min(f-s,e[i].d));            s+=t;e[i^1].d+=t;e[i].d-=t;        }    }    if(s==0)h[x]=0;    return s;}int main(){    int ans=0;    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++)    num[i][j]=++z;    for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++)    {        int k;        scanf("%d%d",&score1[i][j],&k);        for(int l=1;l<=k;l++)        {            int x,y;            scanf("%d%d",&x,&y);x++;y++;            Ins(num[x][y],num[i][j]);            hh[num[x][y]][num[i][j]]=true;        }        if(j>1&&!hh[num[i][j-1]][num[i][j]])Ins(num[i][j-1],num[i][j]);    }    for(int i=1;i<=z;i++)if(!dfn[i])Tarjan(i);    st=z+1;ed=z+2;    for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++)    {        int x=num[i][j];        if(p[bel[x]]>1)addedge(x,ed,inf);        else if(score1[i][j]<0)addedge(x,ed,-score1[i][j]);        else ans+=score1[i][j],addedge(st,x,score1[i][j]);        memset(vis,false,sizeof(vis));vis[x]=true;        for(int l=Last[x];l;l=E[l].next)        {            int y=E[l].y;            if(vis[y])break;vis[y]=true;            addedge(x,y,inf);        }    }    while(bfs())ans-=dfs(st,inf);    printf("%d",ans);}
阅读全文
1 0
原创粉丝点击