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


    题意:N*M的矩阵 每个点上都有一颗植物 僵尸只能从每一行的最右边向左进攻

       每个植物有攻击范围 可以保护在攻击范围内的植物 同时每一颗植物也保护他左边的植物

       摧毁每个植物能获得价值 如果这个植物被保护着就无法摧毁 求最大收益

    题解:看了题解说 一个物品被若干物品保护着 要摧毁它必须先摧毁保护它的东西这种模型

       反向建边就是有向图中的闭合子图这个模型 求闭合子图的最大权十分套路

       把所有正权和源点连容量为权值大小的边 把负权点和汇点连容量为权值的绝对值大小的边

       权值等于0的点连谁都不影响 然后不同点之间有边就连容量为INF的边

       在这个图中跑一遍最小割 然后用正权点权值和 - 最小割就是 闭合子图的最大权了

       但是这个题有一个坑点 如果两个点互相保护 那么这两个点显然就都摧毁不了 所以我们要预先处理成环的点

       先正向连边 然后拓扑排序搞一搞就好了

    #include <bits/stdc++.h>
    using namespace std;
    const int INF = 0x3f3f3f3f;
    
    int n, m, cnt, s, t, maxflow, ans;
    struct node {
        int to, nex, val;
    }E[2000005];
    int head[1005];
    vector<int> g[1005];
    int du[1005], vis[1005], val[1005];
    
    void addedge(int x, int y, int va) {
        E[++cnt].to = y; E[cnt].nex = head[x]; head[x] = cnt; E[cnt].val = va;
        E[++cnt].to = x; E[cnt].nex = head[y]; head[y] = cnt; E[cnt].val = 0;
    }
    
    int get(int x, int y) {return (x - 1) * m + y;}
    
    void topsort() {
        queue<int> que;
        for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            if(!du[get(i, j)]) que.push(get(i, j)), vis[get(i, j)] = 1;
    
        while(!que.empty()) {
            int u = que.front();
            que.pop();
            for(int i = 0; i < g[u].size(); i++) {
                int v = g[u][i];
                du[v]--;
                if(!du[v]) que.push(v), vis[v] = 1;
            }
        }
    }
    
    int dis[1005], inque[1005], cur[1005];
    bool bfs() {
        for(int i = 1; i <= t; i++) dis[i] = INF, inque[i] = 0, cur[i] = head[i];
        queue<int> que; que.push(s);
        dis[s] = 0; inque[s] = 1;
    
        while(!que.empty()) {
            int u = que.front();
            que.pop();
            inque[u] = 0;
            for(int i = head[u]; i; i = E[i].nex) {
                int v = E[i].to;
                if(E[i].val && dis[v] == INF) {
                    dis[v] = dis[u] + 1;
                    if(!inque[v]) {
                        que.push(v);
                        inque[v] = 1;
                    }
                }
            }
        }
        return dis[t] != INF;
    }
    
    int viss;
    int dfs(int x, int flow) {
        if(x == t) {
            viss = 1;
            maxflow += flow;
            return flow;
        }
    
        int used = 0, rflow = 0;
        for(int i = cur[x]; i; i = E[i].nex) {
            cur[x] = i;
            int v = E[i].to;
            if(E[i].val && dis[v] == dis[x] + 1) {
                if(rflow = dfs(v, min(flow - used, E[i].val))) {
                    used += rflow;
                    E[i].val -= rflow;
                    E[i ^ 1].val += rflow;
                    if(used == flow) break;
                }
            }
        }
        if(!used) dis[x] = INF;
        return used;
    }
    
    void dinic() {
        maxflow = 0;
        while(bfs()) {
            viss = 1;
            while(viss) {
                viss = 0;
                dfs(s, INF);
            }
        }
    }
    
    int main() {
        ans = 0;
        cnt = 1;
        scanf("%d%d", &n, &m);
        s = n * m + 1; t = s + 1;
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++) {
                int pos = get(i, j);
                scanf("%d", &val[pos]);
    
                int w; scanf("%d", &w);
                for(int i = 1; i <= w; i++) {
                    int x, y;
                    scanf("%d%d", &x, &y);
                    x++, y++;
                    int pos1 = get(x, y);
                    du[pos1]++; g[pos].push_back(pos1);
                }
                if(j != m) {
                    int pos2 = pos + 1;
                    du[pos]++; g[pos2].push_back(pos);
                }
            }
        topsort();
    
        for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++) {
            int pos = get(i, j);
            if(!vis[pos]) continue;
            if(val[pos] >= 0) addedge(s, pos, val[pos]), ans += val[pos];
            else addedge(pos, t, -val[pos]);
    
            for(int k = 0; k < g[pos].size(); k++) {
                int v = g[pos][k];
                if(vis[v]) addedge(v, pos, INF);
            }
        }
        dinic();
        //for(int i = 1; i <= n * m; i++) cout << vis[i] << endl;
        //cout << ans << " " << maxflow << endl;
        printf("%d
    ", ans - maxflow);
        return 0;
    }
    View Code
  • 相关阅读:
    unity3D打造skybox淡入淡出
    FastGUI for NGUI教程
    (转)oracle的split函数
    (转)oracle嵌套表示例
    (转)pipe row的用法, Oracle split 函数写法.
    (转)Oracle 包(Package)
    (转)Oracle存储过程中的事务
    distinct与order by
    Oracle存储过程使用总结
    (转)Oracle中动态SQL详解
  • 原文地址:https://www.cnblogs.com/lwqq3/p/11655758.html
Copyright © 2020-2023  润新知