• NOI2009 植物大战僵尸


    题目链接:戳我

    最大权闭合子图。一般来说建图方法都是——正权值连S,负权值连T,如果一个节点被选择,其子节点也必须被选择,连一条INF的有向边。求最小割即可,答案就是正权点权值和-最大流——中间的边一定不可能被割掉左边割掉,左边割掉表示不选择,右边割掉表示选择。

    但是有可能出现环的情况,这样子不能直接割。我们考虑先来一个tarjan缩点,给每个点的权值都赋成-inf。

    代码如下:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define S 0
    #define T n*m+1
    #define MAXN 400010
    #define inf 0x3f3f3f3f
    #define check
    using namespace std;
    
    int n,m,cnt1=1,cnt2,cnt,top,ans,tim;
    int head1[MAXN],head2[MAXN],sum[MAXN],dep[MAXN],cur[MAXN];
    int in[MAXN],dfn[MAXN],low[MAXN],ins[MAXN],st[MAXN];
    struct Edge{int nxt,to,dis;}edge[MAXN],pre[MAXN];
    
    inline int id(int x,int y){return m*(x-1)+y;}
    
    inline void add1(int from,int to,int dis,int p)
    {
        edge[++cnt1].nxt=head1[from],edge[cnt1].to=to,edge[cnt1].dis=dis,head1[from]=cnt1;
        edge[++cnt1].nxt=head1[to],edge[cnt1].to=from,edge[cnt1].dis=0,head1[to]=cnt1;
    }
    inline void add2(int from,int to){pre[++cnt2].nxt=head2[from],pre[cnt2].to=to,head2[from]=cnt2;}
    
    inline void tarjan(int x)
    {
        dfn[x]=low[x]=++cnt;
        st[++top]=x;in[x]=1;
        for(int i=head2[x];i;i=pre[i].nxt)
        {
            int v=pre[i].to;
            if(!dfn[v]) tarjan(v),low[x]=min(low[x],low[v]);
            else if(in[v]) low[x]=min(low[x],dfn[v]);
        }
        if(dfn[x]==low[x])
        {
            if(st[top]==x)--top,in[x]=0;
            else
            {
                int v;
                do{v=st[top];top--;in[v]=0;sum[v]=-inf;}while(x!=v);
            }
        }
    }
    
    inline bool bfs()
    {
        queue<int>q;
        memset(dep,0x3f,sizeof(dep));
        memcpy(cur,head1,sizeof(cur));
        q.push(S); dep[S]=0;
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(int i=head1[u];i;i=edge[i].nxt)
            {
                int v=edge[i].to;
                if(dep[v]==0x3f3f3f3f&&edge[i].dis)
                    dep[v]=dep[u]+1,q.push(v); 
            }
        }
        if(dep[T]==0x3f3f3f3f) return false;
        return true;
    }
    inline int dfs(int x,int f)
    {
        if(!f||x==T) return f;
        int used=0,w;
        for(int i=cur[x];i;i=edge[i].nxt)
        {
            int v=edge[i].to;
            cur[x]=i;
            if(dep[v]==dep[x]+1&&(w=dfs(v,min(f,edge[i].dis))))
            {
                edge[i].dis-=w,edge[i^1].dis+=w;
                used+=w,f-=w;
                if(!f) break;
            }
        }
        return used;
    }
    
    inline int dinic()
    {
        int cur_ans=0;
        while(bfs()) cur_ans+=dfs(S,inf);
        return cur_ans;
    }
    
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                int cc;
                if(j<m) add2(id(i,j),id(i,j+1));//printf("[%d %d]
    ",id(i,j),id(i,j+1));
                scanf("%d%d",&sum[id(i,j)],&cc);
                for(int k=1;k<=cc;k++)
                {
                    int cur_x,cur_y;
                    scanf("%d%d",&cur_x,&cur_y);cur_x++,cur_y++;
                    add2(id(cur_x,cur_y),id(i,j));//printf("[%d,%d]
    ",id(cur_x,cur_y),id(i,j));
                }
            }
        }
        for(int i=1;i<T;i++) if(!dfn[i]) tarjan(i);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(sum[id(i,j)]>0) 
                {
                    ans+=sum[id(i,j)],add1(S,id(i,j),sum[id(i,j)],1);
                    //printf("1[%d,%d] %d
    ",S,id(i,j),sum[id(i,j)]);
                }
                else 
                {   
                    add1(id(i,j),T,-sum[id(i,j)],2);
                    //printf("2[%d,%d] %d
    ",id(i,j),T,-sum[id(i,j)]);
                }
                for(int k=head2[id(i,j)];k;k=pre[k].nxt)
                {
                    add1(id(i,j),pre[k].to,inf,3);
                    //printf("3[%d,%d] %d
    ",id(i,j),pre[k].to,inf);
                }
            }
        }
        printf("%d
    ",ans-dinic());
        return 0;
    }
    
  • 相关阅读:
    普通文本输入数学符号的方式
    Chrome crx离线插件下载及安装
    Solidworks常见问题一览
    数学学术资源站点(zz)
    最难读的20个英文单词
    运用html5 canvas做飞机大战游戏(2)
    html
    运用html5 canvas做飞机大战游戏(1)
    js
    css
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10362259.html
Copyright © 2020-2023  润新知