• P2805 [NOI2009]植物大战僵尸(最小割+拓扑排序)


    题意:

      n*m的矩阵,每个位置都有一个植物。每个植物都有一个价值(可以为负),以及一些它可以攻击的位置。从每行的最右面开始放置僵尸,僵尸从右往左行动,当僵尸在植物攻击范围内时会立刻死亡。僵尸每到一个位置可以获得该位置植物的价值。僵尸可以无限放置,求最大的价值和。

    题解:

      这种模型好像叫做最大权闭合子图。

      首先通过拓扑排序将成环的点(即植物互相保护无法走到的点)删掉。

      之后对于剩下的点A,若w > 0,则S→A连权值为w的边。

      若w < 0,则A→T连权值为-w的边。

      若A保护B(即B在A攻击范围内),则B→A连权值为INF的边。

      注意每个点也被它右面的点保护。

      最后跑一边最小割,答案为:正的价值和(即w > 0的和) - 最小割。

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 605;
    const int INF = 2e9;
    int n, m;
    int level[N];
    int iter[N];
    int x, y;
    int w[N], d[N];
    vector<int> g[N];
    vector<int> a;
    struct edge {
        int to, cap, rev;
    };
    vector<edge> G[N];
    void add_edge(int from, int to, int cap) {
        G[from].push_back((edge){to, cap, G[to].size()});
        G[to].push_back((edge){from, 0, G[from].size()-1});
    }
    void bfs(int s) {
        memset(level, -1, sizeof(level));
        queue<int> que;
        level[s] = 0;
        que.push(s);
        while(!que.empty()) {
            int v = que.front(); que.pop();
            int len = G[v].size();
            for(int i = 0; i < len; i++) {
                edge &e = G[v][i];
                if(e.cap > 0 && level[e.to] < 0) {
                    level[e.to] = level[v]+1;
                    que.push(e.to);
                }
            }
        }
    } 
    int dfs(int v, int t, int f) {
        if(v == t) return f;
        int len = G[v].size(); 
        for(int &i = iter[v]; i < len; i++) {
            edge &e = G[v][i];
            if(e.cap > 0 && level[v] < level[e.to]) {
                int d = dfs(e.to, t, min(f, e.cap));
                if(d > 0) {
                    e.cap -= d;
                    G[e.to][e.rev].cap += d;
                    return d;
                }
            }
        }
        return 0;
    } 
    int max_flow(int s, int t) {
        int flow = 0;
        for(;;) {
            bfs(s);
            if(level[t] < 0) return flow;
            memset(iter, 0, sizeof(iter));
            int f;
            while((f = dfs(s, t, INF)) > 0) flow += f;
        }
    } 
    int main() {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n*m; i++) {
            int num;
            scanf("%d%d", &w[i], &num);
            while(num--) {
                scanf("%d%d", &x, &y);
                int id = x*m+y+1;
                g[i].push_back(id);
                d[id]++;
            }
            if(i % m != 1) g[i].push_back(i-1), d[i-1]++;
        }
        queue<int> q;
        for(int i = 1; i <= n*m; i++) if(!d[i]) q.push(i);
        while(!q.empty()) {
            int v = q.front(); q.pop();
            a.push_back(v);
            int len = g[v].size();
            for(int i = 0; i < len; i++) {
                int to = g[v][i];
                d[to]--;
                if(!d[to]) q.push(to);
            }
        }
        int sum = 0;
        int len = a.size();
        for(int i = 0; i < len; i++) {
            int v = a[i];
            if(w[v] >= 0) {
                sum += w[v];
                add_edge(0, v, w[v]);
            }
            else add_edge(v, n*m+1, -w[v]);
            int up = g[v].size();
            for(int j = 0; j < up; j++) add_edge(g[v][j], v, INF);
        }
        printf("%d
    ", sum-max_flow(0, n*m+1));
    }
    View Code
  • 相关阅读:
    git常用指令 github版本回退 reset
    三门问题 概率论
    如何高效的学习高等数学
    数据库6 关系代数(relational algebra) 函数依赖(functional dependency)
    数据库5 索引 动态哈希(Dynamic Hashing)
    数据库4 3层结构(Three Level Architecture) DBA DML DDL DCL DQL
    梦想开始的地方
    java String字符串转对象实体类
    java 生成图片验证码
    java 对象之间相同属性进行赋值
  • 原文地址:https://www.cnblogs.com/Pneuis/p/9858758.html
Copyright © 2020-2023  润新知