zoukankan      html  css  js  c++  java
  • [BZOJ1565][NOI2009]植物大战僵尸-[网络流-最小割+最大点权闭合子图+拓扑排序]

    Description

    传送门

    Solution

    em本题知识点是用网络流求最大点权闭合子图。

    闭合图定义:图中任何一个点u,若有边u->v,则v必定也在图中。

    建图:运用最小割思想,将S向点权为正的点连边,流量为点权;点权为负的点向T连边,流量为点权的绝对值;原图之间的边流量为inf(表明不能割)。答案就是所有正点权之和-该网络流图的最小割(证明还未补qaq)

    是不是觉得这个闭合图定义特别的眼熟?似乎可以套在这道题上。(题意:假如你要吃掉某个植物,需要先吃掉这个植物对应的集合,求最大的能源收入。)假如植物v保护u【ps:在u后面的植物也算作保护u】,则连边u->v。

    当然需要注意,有些植物是RMB玩家哈哈(就是,它们的保护关系可以构成一个环),则这些植物和它们所保护的植物都是不能被吃掉的。RMB玩家可以用拓扑排序完美KO(当然,要把边反向建。原因。。因为我们还要找出所有环上植物们"所保护的植物")

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<queue>
    using namespace std;
    const int inf=1e9;
     
    int h[610],tot=0;
    struct pas{int x,y,nxt,w,op,cost;}g[720000];
    int dep[610],S,T;
    queue<int>q;
    struct DINIC{
    bool bfs()
    {
        int x;
        memset(dep,0,sizeof(dep));dep[S]=1;
        while (!q.empty()) q.pop();
        q.push(S);
        while (!q.empty())
        {
            x=q.front();q.pop();
            for (int i=h[x];i;i=g[i].nxt)
            if (!dep[g[i].y]&&g[i].w)
            {
                dep[g[i].y]=dep[x]+1;
                q.push(g[i].y);
                if (g[i].y==T) return 1;
            }
        }
        return 0;
    }
    int dfs(int x,int flow)
    {
        if (x==T||(!flow))return flow;
        int temp=0,js;
        for (int i=h[x];i;i=g[i].nxt)
        if (dep[g[i].y]==dep[x]+1&&g[i].w)
        {
            js=dfs(g[i].y,min(flow,g[i].w));
            if (js)
            {
                g[i].w-=js;
                g[g[i].op].w+=js;
                temp+=js;
                flow-=js;
                if (!flow) return temp;
            }
        }
        if (!temp) dep[x]=0;
        return temp;
    }
        int dinic()
        {
            int ans=0;
            while (bfs()) 
            ans+=dfs(S,inf);
            return ans;
        } 
     }D;
       
    void add(int x,int y,int w)
    {
        g[++tot].x=x;g[tot].y=y;g[tot].w=w;g[tot].nxt=h[x];g[tot].op=tot+1;h[x]=tot;
        g[++tot].x=y;g[tot].y=x;g[tot].w=0;g[tot].nxt=h[y];g[tot].op=tot-1;h[y]=tot;
    }
     
    int n,m,cnt,r,c,TOT,_v[610];
    int id(int x,int y) {return (x-1)*m+y;}
    bool not_cir[610];int d[610];
     
    pas e[710010];
    int e_tot=0,e_h[610];
    void adde(int x,int y)
    {
        e[++e_tot]=pas{x,y,e_h[x],0,0,0};e_h[x]=e_tot;
        d[y]++;
    }
    void check()
    {
        while (!q.empty()) q.pop();
        for (int i=1;i<=n*m;i++) if (!d[i]) q.push(i),not_cir[i]=1;
        while (!q.empty())
        {
            int x=q.front();q.pop();
            for (int i=e_h[x];i;i=e[i].nxt)
            {
                d[e[i].y]--;
                if (!d[e[i].y]) not_cir[e[i].y]=1,q.push(e[i].y);
            }
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        S=0;T=n*m+1;
        for (int i=1;i<=n;i++) for (int j=1;j<=m;j++)
        {
            scanf("%d",&_v[id(i,j)]);
            scanf("%d",&cnt);
            for (int k=1;k<=cnt;k++)
            {
                scanf("%d%d",&r,&c);adde(id(i,j),id(r+1,c+1));
            }
            if (j!=m) adde(id(i,j+1),id(i,j));
        }
        check();
        for (int i=1;i<=e_tot;i++) if (not_cir[e[i].x]&&not_cir[e[i].y])add(e[i].y,e[i].x,inf);
        for (int i=1;i<=n*m;i++) if (not_cir[i]) {if (_v[i]>0) add(S,i,_v[i]),TOT+=_v[i];else add(i,T,-_v[i]);}
        int ans=0;
        while (D.bfs())
            ans+=D.dfs(S,inf);
        printf("%d",TOT-ans);
    }
  • 相关阅读:
    A1023 Have Fun with Numbers (20分)(大整数四则运算)
    A1096 Consecutive Factors (20分)(质数分解)
    A1078 Hashing (25分)(哈希表、平方探测法)
    A1015 Reversible Primes (20分)(素数判断,进制转换)
    A1081 Rational Sum (20分)
    A1088 Rational Arithmetic (20分)
    A1049 Counting Ones (30分)
    A1008 Elevator (20分)
    A1059 Prime Factors (25分)
    A1155 Heap Paths (30分)
  • 原文地址:https://www.cnblogs.com/coco-night/p/9622909.html
Copyright © 2011-2022 走看看