zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    fullCalendar改造计划之带农历节气节假日的万年历(转)
    Linked List Cycle
    Remove Nth Node From End of List
    Binary Tree Inorder Traversal
    Unique Binary Search Trees
    Binary Tree Level Order Traversal
    Binary Tree Level Order Traversal II
    Plus One
    Remove Duplicates from Sorted List
    Merge Two Sorted Lists
  • 原文地址:https://www.cnblogs.com/Pneuis/p/9858758.html
Copyright © 2011-2022 走看看