zoukankan      html  css  js  c++  java
  • b2OJ_1565_[NOI2009]植物大战僵尸_拓扑排序+最大权闭合子图

    b2OJ_1565_[NOI2009]植物大战僵尸_拓扑排序+最大权闭合子

    题意:n*m个植物,每个植物有分数(可正可负),和能保护植物的位置。只能从右往左吃,并且不能吃正被保护着的,可以一个不吃,求获得的最大分数。

    分析:把每个植物向能保护它的植物连边。源点连正权点,负权点连汇点。

    考虑在一个环上的植物是吃不到的,我们可以用拓扑排序确定哪些是能吃的。

    然后求一遍最大权闭合子图就是答案。

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <queue>
    using namespace std;
    #define S (n*m+1)
    #define T (n*m+2)
    #define P(x,y) (m*(x-1)+y) 
    #define inf 100000000
    int head[700],to[1000010],nxt[1000010],flow[1000010],c[1000010],cnt=1,dep[700];
    int n,m,can[700],sum,val[700];
    void add(int u,int v,int f)
    {
        to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;flow[cnt]=f;
        to[++cnt]=u;nxt[cnt]=head[v];head[v]=cnt;flow[cnt]=0;
    }
    bool bfs()
    {
        queue <int> q;
        memset(dep,0,sizeof(dep));
        q.push(S);dep[S]=1;
        while(q.size())
        {
            int x=q.front();q.pop();
            for(int i=head[x];i;i=nxt[i])
            {
                if(!dep[to[i]]&&flow[i]&&can[to[i]])
                {
                    dep[to[i]]=dep[x]+1;
                    q.push(to[i]);
                }
            }
        }
        return dep[T];
    }
    int dfs(int x,int mf)
    {
        if(x==T)return mf;
        int nf=0;
        for(int i=head[x];i;i=nxt[i])
        {
            if(dep[to[i]]==dep[x]+1&&flow[i]&&can[to[i]])
            {
                int tmp=dfs(to[i],min(flow[i],mf-nf));
                nf+=tmp;
                flow[i]-=tmp;
                flow[i^1]+=tmp; 
                if(nf==mf)break;
            }
        }
        dep[x]=0;
        return nf;
    }
    void dinic()
    {
        int ans=0,f;
        while(bfs())
        {
            while(f=dfs(S,inf))
            {
                ans+=f; 
            }
        }
        printf("%d",sum-ans);
    }
    void topsort()
    {
        queue <int> q;
        for(int i=1;i<=T;i++)
        {
            if(!c[i])q.push(i); 
        }
        while(q.size())
        {
            int x=q.front();q.pop();
            can[x]=1;
            if(val[x]>0)sum+=val[x];
            for(int i=head[x];i;i=nxt[i])
            {
                c[to[i]]--;
                if(c[to[i]]==0)q.push(to[i]);
            }
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        int x,y,z,w;
        for(int i=1;i<=n*m;i++)
        {
            scanf("%d%d",&x,&y);
            val[i]=x;
            if(x>0)add(S,i,x),c[S]++;
            else add(i,T,-x),c[i]++;
            if(i%m)add(i,i+1,inf),c[i]++;
            while(y--)
            {
                scanf("%d%d",&z,&w);
                add(P(z+1,w+1),i,inf);  
                c[P(z+1,w+1)]++;
            }
        }
        topsort();
        dinic();
    }
      
    /***************************************************************
        Problem: 1580
        User: 20170105
        Language: C++
        Result: Accepted
        Time:320 ms
        Memory:16704 kb
    ****************************************************************/
    
  • 相关阅读:
    数字三角形
    嵌套矩阵问题
    NKOJ1236 a^b
    历届试题 最大子阵
    【动态规划】最大连续子序列和,最大子矩阵和,最大m子段和
    历届试题 翻硬币
    历届试题 带分数
    用户模板和用户场景
    学习进度——第九周
    最大子数组——回调
  • 原文地址:https://www.cnblogs.com/suika/p/8424481.html
Copyright © 2011-2022 走看看