zoukankan      html  css  js  c++  java
  • BZOJ1565 [NOI2009]植物大战僵尸 【最大权闭合子图 + tarjan缩点(或拓扑)】

    题目

    这里写图片描述

    输入格式

    这里写图片描述

    输出格式

    仅包含一个整数,表示可以获得的最大能源收入。注意,你也可以选择不进行任何攻击,这样能源收入为0。

    输入样例

    3 2

    10 0

    20 0

    -10 0

    -5 1 0 0

    100 1 2 1

    100 0

    输出样例

    25

    提示

    在样例中, 植物P1,1可以攻击位置(0,0), P2, 0可以攻击位置(2,1)。
    一个方案为,首先进攻P1,1, P0,1,此时可以攻击P0,0 。共得到能源收益为(-5)+20+10 = 25。注意, 位置(2,1)被植物P2,0保护,所以无法攻击第2行中的任何植物。
    【大致数据规模】
    约20%的数据满足1 ≤ N, M ≤ 5;
    约40%的数据满足1 ≤ N, M ≤ 10;
    约100%的数据满足1 ≤ N ≤ 20,1 ≤ M ≤ 30,-10000 ≤ Score ≤ 10000 。

    题解

    僵尸想吃一个植物,首先得吃掉它前面的植物和保护它的植物
    这就是有附属关系的最大权选择问题,即最大权闭合子图

    但是要注意图中的环是无敌的,我们要忽略掉这些点
    可以用tarjan或拓扑找环
    还没完
    被环保护的点也是无敌的,所以还要从环出发排除掉被环保护的点【一开始没注意到这个WA了2发】

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define Redge(u) for (int k = h[u]; k != -1; k = ed[k].nxt)
    using namespace std;
    const int maxn = 1005,maxm = 2000005,INF = 1000000000;
    inline int RD(){
        int out = 0,flag = 1; char c = getchar();
        while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
        while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}
        return out * flag;
    }
    int s[maxn],id[22][32],N,M,cnt = 0,S,T,f[maxn];
    int h[maxn],ne = 0;
    struct EDGE{int to,nxt,f;}ed[maxm];
    void build(int u,int v,int f){
        ed[ne] = (EDGE){v,h[u],f}; h[u] = ne++;
        ed[ne] = (EDGE){u,h[v],0}; h[v] = ne++;
    }
    int dfn[maxn],low[maxn],Scc[maxn],scci = 0,Siz[maxn],st[maxn],top = 0,Cnt = 0;
    void dfs(int u){
        low[u] = dfn[u] = ++Cnt;
        st[++top] = u; int to;
        Redge(u){
            if (k & 1) continue;
            if (!dfn[to = ed[k].to]) dfs(to);
            if (!Scc[to]) low[u] = min(low[u],low[to]);
        }
        if (dfn[u] == low[u]){
            scci++;
            do {Scc[st[top]] = scci; Siz[scci]++;}while (st[top--] != u);
        }
    }
    void tarjan(){
        REP(i,cnt) if (!dfn[i]) dfs(i);
    }
    int d[maxn],vis[maxn],cur[maxn];
    bool bfs(){
        queue<int> q; int u,to;
        for (int i = S; i <= T; i++) d[i] = INF,vis[i] = false;
        q.push(S); vis[S] = true; d[S] = 0;
        while (!q.empty()){
            u = q.front(); q.pop();
            Redge(u) if (ed[k].f && !f[to = ed[k].to] && !vis[to]){
                d[to] = d[u] + 1; vis[to] = true; q.push(to);
            }
        }
        return vis[T];
    }
    int dfs(int u,int minf){
        if (u == T || !minf) return minf;
        int flow = 0,f,to;
        if (cur[u] == -2) cur[u] = h[u];
        for (int& k = cur[u]; k != -1; k = ed[k].nxt)
            if (d[to = ed[k].to] == d[u] + 1 && (f = dfs(to,min(ed[k].f,minf)))){
                ed[k].f -= f; ed[k ^ 1].f += f;
                flow += f; minf -= f;
                if (!minf) break;
            }
        return flow;
    }
    int maxflow(){
        int flow = 0;
        while (bfs()){
            fill(cur,cur + maxn,-2);
            flow += dfs(S,INF);
        }
        return flow;
    }
    void dfs1(int u){
        f[u] = true;
        Redge(u) if ((k & 1) && !f[ed[k].to]) dfs1(ed[k].to);
    }
    int main(){
        memset(h,-1,sizeof(h));
        N = RD(); M = RD(); int t,x,y,tot = 0;
        REP(i,N) REP(j,M) id[i - 1][j - 1] = ++cnt;
        for (int i = 0; i < N; i++)
            for (int j = 0; j < M; j++)
                if (j + 1 < M)
                    build(id[i][j],id[i][j + 1],INF);
        S = 0; T = cnt + 1;
        for (int i = 1; i <= cnt; i++){
            s[i] = RD(); t = RD();
            while (t--) x = RD(),y = RD(),build(id[x][y],i,INF);
        }
        tarjan();
        REP(i,cnt) if (Siz[Scc[i]] > 1) dfs1(i);
        REP(i,cnt) if (!f[i]){
            if (s[i] >= 0) build(S,i,s[i]),tot += s[i];
            else build(i,T,-s[i]);
        }
        printf("%d",tot - maxflow());
        return 0;
    }
    
  • 相关阅读:
    Linux-exec族函数
    Linux-竟态初步引入
    Linux-waitpid介绍
    Java基础:Java运算符:算术运算符
    Java中的算术运算符
    JAVA冒泡排序
    引用 java的一些基本概念
    Tomcat服务器的下载安装跟基本配置
    Tomcat配置Web站点
    Tomcat+JSP经典配置实例
  • 原文地址:https://www.cnblogs.com/Mychael/p/8282722.html
Copyright © 2011-2022 走看看