• [NOI2009]植物大战僵尸


    题目:洛谷P2805、BZOJ1565。

    题目大意:

    在n×m的网格上,每个格子有植物,吃了每个植物能获得一些价值(可能为负),每个植物可能会保护另一些植物,要吃被保护的植物必须先消灭该植物。你可以在最右边放僵尸。问最大价值。

    解题思路:

    PVZ真好玩

    首先,右边的植物也是保护左边的植物的。

    然后,就是最大权闭合子图模型。最大流即可。

    从S向价值为正的植物连容量为价值的边;从价值为负的植物向T连容量为价值的相反数的边。

    从被保护的植物向保护的植物连容量inf的边。

    答案即为价值为正的植物的价值总和-最大流。

    然鹅发现并过不去。因为有环!植物和植物可能存在着循环保护,然后这些植物就无敌了(无敌植物所保护的其他植物也无敌)。

    故我们首先要用Tarjan找强连通分量,把环找出来,然后删掉这些无敌的点(包括其保护的点等)。

    接着再建图跑网络流即可。

    C++ Code:

    #include<bits/stdc++.h>
    const int S=0,T=6665,inf=0x3fffffff;
    inline int readint(){
        int c=getchar(),d=0,f=0;
        for(;!isdigit(c);c=getchar())f=c=='-';
        for(;isdigit(c);c=getchar())
        d=(d<<3)+(d<<1)+(c^'0');
        return f?-d:d;
    }
    int n,m,sco[666],low[666],dfn[666],idx=0,vis[666],head[6666],iter[6666],level[6666],cnt=1;
    bool ok[666];
    inline int num(int a,int b){return(a-1)*m+b;}
    inline int min(int a,int b){return a<b?a:b;}
    std::vector<int>v[666];
    std::stack<int>s;
    void tarjan(int now){
        low[now]=dfn[now]=++idx;
        s.push(now);vis[now]=1;
        for(int i=v[now].size()-1;~i;--i)
        if(!dfn[v[now][i]]){
            tarjan(v[now][i]);
            low[now]=min(low[now],low[v[now][i]]);
        }else
        if(vis[v[now][i]])low[now]=min(low[now],dfn[v[now][i]]);
        if(low[now]==dfn[now]){
            int sz=1;
            for(;s.top()!=now;++sz){
                ok[s.top()]=false;
                vis[s.top()]=0;
                s.pop();
            }
            vis[now]=0;
            s.pop();
            if(sz>1)ok[now]=false;
        }
    }
    struct edge{
        int to,nxt,cap;
    }e[2333333];
    inline void addedge(int from,int to,int flow){
        e[++cnt]=(edge){to,head[from],flow};
        head[from]=cnt;
        e[++cnt]=(edge){from,head[to],0};
        head[to]=cnt;
    }
    std::queue<int>q;
    void bfs(){
        level[S]=1;
        for(q.push(S);!q.empty();){
            int u=q.front();
            q.pop();
            for(int i=head[u];~i;i=e[i].nxt)
            if(e[i].cap&&!~level[e[i].to]){
                level[e[i].to]=level[u]+1;
                q.push(e[i].to);
            }
        }
    }
    int dfs(int u,int f){
        if(!f||u==T)return f;
        for(int& i=iter[u];~i;i=e[i].nxt)
        if(e[i].cap&&level[e[i].to]>level[u]){
            int d=dfs(e[i].to,min(f,e[i].cap));
            if(d){
                e[i].cap-=d;
                e[i^1].cap+=d;
                return d;
            }else level[e[i].to]=-1;
        }
        return 0;
    }
    int dinic(){
        for(int flow=0,f;;){
            memset(level,-1,sizeof iter);
            if(bfs(),!~level[T])return flow;
            memcpy(iter,head,sizeof iter);
            while(f=dfs(S,inf))flow+=f;
        }
    }
    void color(int now){
        for(int i=v[now].size()-1;~i;--i)
        if(ok[v[now][i]]){
            ok[v[now][i]]=false;
            color(v[now][i]);
        }
    }
    int main(){
        n=readint(),m=readint();
        for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j){
            int id=num(i,j);
            sco[id]=readint();
            for(int cc=readint();cc--;){
                int x=readint()+1,y=readint()+1;
                v[id].push_back(num(x,y));
            }
            if(j>1)v[id].push_back(id-1);
        }
        memset(dfn,0,sizeof dfn);
        memset(vis,0,sizeof vis);
        memset(head,-1,sizeof head);
        memset(ok,1,sizeof ok);
        for(int i=1;i<=n*m;++i)
        if(!dfn[i])tarjan(i);
        int sm=0;
        for(int i=1;i<=n*m;++i)
        if(!ok[i])color(i);
        for(int i=1;i<=n*m;++i)
        if(ok[i]){
            if(sco[i]>0)addedge(S,i,sco[i]);else
            addedge(i,T,-sco[i]);
            sm+=(sco[i]>0)*sco[i];
            for(int j=v[i].size()-1;~j;--j)
            if(ok[v[i][j]])addedge(v[i][j],i,inf);
        }
        printf("%d
    ",sm-dinic());
        return 0;
    }
  • 相关阅读:
    cisco telnet(转载)
    华为bfd配置步骤
    cisco ssh实验--附带配置脚本-2019.11.19
    远程设备管理opendx平台搭建-server,agent以及front实际搭建
    远程设备管理opendx平台搭建-appium和adb的安装
    华为交换机sflow配置
    华为交换机netstream配置
    centos6虚拟机复制后修改网卡
    docker基本操作
    esxi 6 添加硬盘、网卡
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/9307462.html
Copyright © 2020-2023  润新知