JDOJ-1580: [NOI2009]植物大战僵尸 最大权闭合子图

[文章目录]

Description

给你一张网格,每个格点上有一植物,植物有自己的分数,分数有正有负。想吃一个植物必须将其前面的植物也吃掉,并且给出有一些植物可以保护其他植物(就是说想吃一个植物,必须把保护她的植物和其前面的植物都吃掉)。问从网格的右边怎么吃才能得到最高的分数。1<=N<=201<=M<=30-10000<=Score<=10000

网络流,作一个图,被保护的植物指向保护她的植物,跑一遍最大权闭合子图。

不过,想想,金牛植物可能有无敌金身啊(环)。并且被金牛指向的植物也永远吃不了啊。并且被金牛植物指向的指向的......

再想想最大权闭合子图定义(woc???明摆着如果有环就要么直接都拿走,或者都撇掉)。所以,hhh,拓扑一下就好了(代码恶心)。然后再跑一遍最大权闭合子图。

我的代码建了两张图(ckh直接建立原图双向边,后向弧,标记边进行拓扑,然后标记点,bfs时直接略过不能吃的点(dis==-1),直接一张图搞定%%% %%% %%%)

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m,scor[30][40],s,t,sum,ans;
queue<int>q;
int head[700],rd[700],to[600000],nxt[600000],cnt;
bool v[700];
int read()
{
    char ch=getchar();int re=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')
        re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
    return re*f;
}
void add(int x,int y)
{
    to[++cnt]=y;
    nxt[cnt]=head[x];
    head[x]=cnt;
}
void topsort()
{
    for(int i=1*m+1;i<=n*m+m;i++)
        if(!rd[i]) v[i]=1,q.push(i);
    while(!q.empty())
    {
        int tmp=q.front();q.pop();
        for(int y,i=head[tmp];i;i=nxt[i])
        {
            rd[y=to[i]]--;
            if(!rd[y]){v[y]=1;q.push(y);}
        }
    }
}
int whead[800],wto[1200000],wnxt[1200000],wf[1200000],wcnt=1;
void add_web(int x,int y,int z)
{
    wto[++wcnt]=y;
    wnxt[wcnt]=whead[x];
    wf[wcnt]=z;
    whead[x]=wcnt;

    wto[++wcnt]=x;
    wnxt[wcnt]=whead[y];
    wf[wcnt]=0;
    whead[y]=wcnt;
}
int dis[800];
bool bfs()
{
    memset(dis,-1,sizeof(dis));
    while(q.size())q.pop();
    q.push(s),dis[s]=0;
    while(!q.empty())
    {
        int tmp=q.front();q.pop();
        for(int y,i=whead[tmp];i;i=wnxt[i])
            if(wf[i]&&dis[y=wto[i]]<0)
            {
                dis[y]=dis[tmp]+1;
                if(y==t) return true;
                q.push(y);
            }
    }
    return false;
}
int dinic(int x,int flow)
{
    if(x==t) return flow;
    int k,tmp=flow;
    for(int y,i=whead[x];i;i=wnxt[i])
        if(wf[i]>0&&dis[y=wto[i]]==dis[x]+1)
        {
            k=dinic(y,min(tmp,wf[i]));
            if(k==0) dis[y]=-1;//
            tmp-=k;wf[i]-=k;wf[i^1]+=k;
            if(tmp==0) break;
        }
    return flow-tmp;
}
int main()
{
    cin>>n>>m;
    s=n*m+m+1,t=n*m+m+2;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(j!=m)
            {add(i*m+j+1,i*m+j);rd[i*m+j]++;} 
            scor[i][j]=read();
            int tmp=read();
            while(tmp--)
            {
                int x=read(),y=read();
                add(i*m+j,x*m+m+y+1);
                rd[x*m+m+y+1]++;
            }
        }
    }
    /*for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            printf("%d ",i*m+j);
        }
        puts("");
    }
    for(int i=1*m+1;i<=n*m+m;i++)
    {
        printf("%d rd %d :",i,rd[i]);
        for(int j=head[i];j;j=nxt[j])
            printf("%d ",to[j]);
        puts("");
    }*/
    topsort();
    /*for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
            printf("%d ",v[i*m+j]);
        puts("");
    }*/
    for(int i=1;i<=n;i++) for(int x,j=1;j<=m;j++)
    {
        if(!v[i*m+j]) continue;
        if(scor[i][j]>0) add_web(s,i*m+j,scor[i][j]),sum+=scor[i][j];
        else add_web(i*m+j,t,-scor[i][j]);
        for(int y,k=head[i*m+j];k;k=nxt[k])
        {
            if(!v[y=to[k]]) continue;
            add_web(y,i*m+j,1<<30);
        }
    }
    while(bfs()) ans+=dinic(s,1<<30);
    printf("%d",sum-ans);
    return 0;
}

 

发表评论

邮箱地址不会被公开。 必填项已用*标注