zoukankan      html  css  js  c++  java
  • BZOJ 1565 [NOI2009]植物大战僵尸 | 网络流

    传送门

    BZOJ 1565

    题解

    这道题也是个经典的最大权闭合子图……

    复习一下最大权闭合子图是什么?
    就是一个DAG上,每个点有个或正或负的点权,有的点依赖于另外一些点(如果选这个点,则被依赖点必选),问选出一些点的权值和最大是多少。

    这个问题怎么解决?
    网络流建图,被依赖点向依赖点连INF的边,若某点权为正则源点向它连相应容量的边,否则它向汇点连点权的绝对值容量的边。

    问题是……这道题是有环的……
    有环也没关系,按照题意,环上的点都不能选,那么直接让环上的所有点向汇点连INF边即可。

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    #include <ctime>
    using namespace std;
    typedef long long ll;
    #define enter putchar('
    ')
    #define space putchar(' ')
    template <class T>
    void read(T &x){
        char c;
        bool op = 0;
        while(c = getchar(), c > '9' || c < '0')
            if(c == '-') op = 1;
        x = c - '0';
        while(c = getchar(), c >= '0' && c <= '9')
            x = x * 10 + c - '0';
        if(op) x = -x;
    }
    template <class T>
    void write(T x){
        if(x < 0) putchar('-'), x = -x;
        if(x >= 10) write(x / 10);
        putchar('0' + x % 10);
    }
    
    const int N = 605, M = 1000005, INF = 0x3f3f3f3f;
    int n, m, src, des, ans;
    int _adj[N], _nxt[M], _go[M], _ecnt;
    #define id(x, y) (x * m + y + 1)
    int ecnt = 1, adj[N], cur[N], dis[N], nxt[M], go[M], cap[M];
    int low[N], dfn[N], idx, stk[N], top;
    bool ins[N], mark[N];
    
    void ADD(int u, int v, int w){
        go[++ecnt] = v;
        nxt[ecnt] = adj[u];
        adj[u] = ecnt;
        cap[ecnt] = w;
    }
    void add(int u, int v, int w){
        ADD(u, v, w);
        ADD(v, u, 0);
    }
    void _add(int u, int v){
        _go[++_ecnt] = v;
        _nxt[_ecnt] = _adj[u];
        _adj[u] = _ecnt;
    }
    bool bfs(){
        static int que[N], qr;
        for(int i = 1; i <= des; i++)
            cur[i] = adj[i], dis[i] = -1;
        dis[src] = 0, que[qr = 1] = src;
        for(int ql = 1; ql <= qr; ql++)
            for(int u = que[ql], e = adj[u], v; e; e = nxt[e])
                if(cap[e] && dis[v = go[e]] == -1)
                    dis[v] = dis[u] + 1, que[++qr] = v;
        return dis[des] != -1;
    }
    int dfs(int u, int flow){
        if(u == des) return flow;
        int ret = 0;
        for(int &e = cur[u], v; e; e = nxt[e])
            if(cap[e] && dis[v = go[e]] == dis[u] + 1){
                int delta = dfs(v, min(cap[e], flow - ret));
                if(delta){
                    cap[e] -= delta;
                    cap[e ^ 1] += delta;
                    ret += delta;
                    if(ret == flow) return ret;
                }
            }
        dis[u] = -1;
        return ret;
    }
    int maxflow(){
        int ret = 0;
        while(bfs()) ret += dfs(src, INF);
        return ret;
    }
    void tarjan(int u){
        stk[++top] = u, ins[u] = 1;
        low[u] = dfn[u] = ++idx;
        for(int e = _adj[u], v; e; e = _nxt[e])
            if(v = _go[e], !dfn[v])
                tarjan(v), low[u] = min(low[u], low[v]);
            else if(ins[v])
                low[u] = min(low[u], dfn[v]);
        if(low[u] == dfn[u]){
            int v = stk[top];
            if(v == u) top--, ins[u] = 0;
            else
                while(v != u){
                    ins[v = stk[top--]] = 0;
                    mark[v] = 1;
                }
        }
    }
    
    int main(){
        read(n), read(m), src = n * m + 1, des = n * m + 2;
        for(int i = 0, k, w, x, y, num = 1; i < n; i++)
            for(int j = 0; j < m; j++, num++){
                if(j) _add(num - 1, num), add(num - 1, num, INF);
                read(w), read(k);
                if(w >= 0) add(src, num, w), ans += w;
                else add(num, des, -w);
                while(k--){
                    read(x), read(y);
                    _add(id(x, y), num);
                    add(id(x, y), num, INF);
                }
            }
        for(int i = 1; i <= n * m; i++)
            if(!dfn[i]) tarjan(i);
        for(int i = 1; i <= n * m; i++)
            if(mark[i]) add(i, des, INF);
        write(ans - maxflow()), enter;
    
        return 0;
    }
    
  • 相关阅读:
    搜索引擎ElasticSearch系列(四): ElasticSearch2.4.4 sql插件安装
    搜索引擎ElasticSearch系列(三): ElasticSearch2.4.4 bigdesk插件安装
    搜索引擎ElasticSearch系列(二): ElasticSearch2.4.4 Head插件安装
    搜索引擎ElasticSearch系列(一): ElasticSearch2.4.4环境搭建
    LumiSoft.Net 收发邮件
    搜索引擎Solr6.2.1 索引富文本(word/pdf/txt/html)
    用异或提取出数组中的单独数
    买卖股票的最佳时机 II
    二叉树的路径总和
    SpringBeanUtils的部分方法类
  • 原文地址:https://www.cnblogs.com/RabbitHu/p/BZOJ1565.html
Copyright © 2011-2022 走看看