bzoj1565: [NOI2009]植物大战僵尸

其实一开始看到题意很长就不想做。。

其实一开始想什么spfa什么DP什么的。。

而这题是网络流(好像之前在竞赛室的时候听到队长骂这题stm网络流很难写,感觉还好啊,一中午写完了,2A)

直接网络流显然搞不定,因为每个点有点值啊,费用流感觉也不对,想试试最小割,前天吃饭的时候突然想到:诶这题有负数?那搞搞最大权闭合子图!

显然就正负分开st集合和ed集合,然后我就发现中间保护建的边要到inf,可最大权闭合子图不是sum-最小割吗?昨天走的时候O老师(%%%)才告诉我是正权sum-最小割

然后就这样建,发现数据有环,那就要用topsort判环,但是有个要注意的,假如x被y保护,千万建边要建成y->x,如果建成x->y,假如x在环里面,那y的入度肯定不是0,但是实际上是y保护x,x无法被吃掉对于y是没有影响的。

好感动。。。第二题最大权闭合子图居然看出来了而且2A。。。

#include<cstdio>
#include<iostream> 
#include<cstring>
using namespace std;

int n,m,st,ed,sum;
int w[610];

struct enode
{
    int x,y,next;
}e[410000];int elen,elast[610];
void eins(int x,int y)
{
    elen++;
    e[elen].x=x;e[elen].y=y;
    e[elen].next=elast[x];elast[x]=elen;
}

int ru[610],top,sta[610];
void topsort()
{
    top=0;
    for(int i=1;i<=n*m+2;i++)
        if(ru[i]==0)sta[++top]=i;
        
    while(top!=0)
    {
        int x=sta[top];top--;
        for(int k=elast[x];k;k=e[k].next)
        {
            int y=e[k].y;
            ru[y]--;
            if(ru[y]==0)sta[++top]=y;
        }
    }
    
    sum=0;
    for(int i=1;i<=n*m;i++)
        if(ru[i]==0&&w[i]>=0)sum+=w[i];
}


struct node
{
    int x,y,c,next,other;
}a[810000];int len,last[610];
void ins(int x,int y,int c)
{
    int k1,k2;
    
    len++;k1=len;
    a[len].x=x;a[len].y=y;a[len].c=c;
    a[len].next=last[x];last[x]=len;
    
    len++;k2=len;
    a[len].x=y;a[len].y=x;a[len].c=0;
    a[len].next=last[y];last[y]=len;
    
    a[k1].other=k2;
    a[k2].other=k1;
}
void composition()
{
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<=elen;i++)
    {
        int x=e[i].x,y=e[i].y;
        if(ru[x]==0&&ru[y]==0)ins(x,y,999999999);
    }
    
    for(int i=1;i<=n*m;i++)
        if(ru[i]==0) 
            if(w[i]>=0)ins(i,ed,w[i]);
            else        ins(st,i,-w[i]);
}

int h[610],list[610];
bool bt_h()
{
    memset(h,0,sizeof(h));h[st]=1;
    int head=1,tail=2;list[1]=st;
    while(head!=tail)
    {
        int x=list[head];
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(h[y]==0&&a[k].c>0)
            {
                h[y]=h[x]+1;
                list[tail]=y;
                tail++;
            }
        }
        head++;
    }
    if(h[ed]==0)return false;
    return true;
}
int findflow(int x,int f)
{
    if(x==ed)return f;
    int s=0;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(h[y]==h[x]+1&&a[k].c>0&&s<f)
        {
            int t=findflow(y,min(a[k].c,f-s));
            s+=t;a[k].c-=t;a[a[k].other].c+=t;
        }
    }
    if(s==0)h[x]=0;
    return s;
}

int point(int x,int y){return x*m+y+1;}
int main()
{
    int T,x,y;
    scanf("%d%d",&n,&m);
    st=n*m+1;ed=n*m+2;

    elen=0;memset(elast,0,sizeof(elast));
    memset(ru,0,sizeof(ru));
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            int p=point(i,j);
            scanf("%d",&w[p]);
            
            //我所能保护的 
            int pro;
            if(j!=0)
            {
                pro=point(i,j-1);
                eins(p,pro), ru[pro]++;
            }
            scanf("%d",&T);
            while(T--)
            {
                scanf("%d%d",&x,&y);
                pro=point(x,y);
                eins(p,pro), ru[pro]++;
            }
        }
    }
    
    topsort();
    composition();
    
    int ans=0;
    while(bt_h()==true)
    {
        ans+=findflow(st,999999999);
    }
    printf("%d
",sum-ans);
    return 0;
}
原文地址:https://www.cnblogs.com/AKCqhzdy/p/7878868.html