zoukankan      html  css  js  c++  java
  • 有向图破坏(最小割,最小点权覆盖)

    题意

    给定一个(n)个点,(m)条边的有向图。

    现在有一种操作,就是可以将任意点的所有出边或者所有入边删掉。

    已知对于第(i)个点,将所有射入该点的边移除所需的花费为(W^+_i),将所有从该点射出的边移除所需的花费为(W^−_i)

    求移除所有边的最小花费。

    思路

    考察一条边((u, v)),要删除这条边,要么花费(W^−_u),要么花费(W^+_v)

    因此就可以将一个点拆成两个点,建立二分图。该问题就是求二分图的最小点权覆盖集。

    左边有(n)个点,代表射入点,虚拟源点(S)向这些点连容量是(W^+_i)的边;右边有(n)个点,代表射出点,这些点向虚拟汇点(T)连容量是(W^-_i)的边。中间的边容量是(infty)

    跑最小割求最小点权覆盖集即可。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    
    using namespace std;
    
    const int N = 210, M = 10410, inf = 1e8;
    
    int n, m, S, T;
    int h[N], e[M], ne[M], f[M], idx;
    int cur[N], d[N];
    bool st[N];
    
    void add(int a, int b, int c)
    {
        e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx ++;
        e[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx ++;
    }
    
    bool bfs()
    {
        memset(d, -1, sizeof(d));
        queue<int> que;
        que.push(S);
        d[S] = 0, cur[S] = h[S];
        while(que.size()) {
            int t = que.front();
            que.pop();
            for(int i = h[t]; ~i; i = ne[i]) {
                int ver = e[i];
                if(d[ver] == -1 && f[i]) {
                    d[ver] = d[t] + 1;
                    cur[ver] = h[ver];
                    if(ver == T) return true;
                    que.push(ver);
                }
            }
        }
        return false;
    }
    
    int find(int u, int limit)
    {
        if(u == T) return limit;
        int flow = 0;
        for(int i = cur[u]; ~i && flow < limit; i = ne[i]) {
            cur[u] = i;
            int ver = e[i];
            if(d[ver] == d[u] + 1 && f[i]) {
                int t = find(ver, min(f[i], limit - flow));
                if(!t) d[ver] = -1;
                f[i] -= t, f[i ^ 1] += t, flow += t;
            }
        }
        return flow;
    }
    
    int dinic()
    {
        int res = 0, flow;
        while(bfs()) {
            while(flow = find(S, inf)) {
                res += flow;
            }
        }
        return res;
    }
    
    void dfs(int u)
    {
        st[u] = true;
        for(int i = h[u]; ~i; i = ne[i]) {
            int j = e[i];
            if(f[i] && !st[j]) {
                dfs(j);
            }
        }
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
        S = 0, T = 2 * n + 1;
        memset(h, -1, sizeof(h));
        for(int i = 1; i <= n; i ++) {
            int w;
            scanf("%d", &w);
            add(S, i, w);
        }
        for(int i = 1; i <= n; i ++) {
            int w;
            scanf("%d", &w);
            add(n + i, T, w);
        }
        while(m --) {
            int a, b;
            scanf("%d%d", &a, &b);
            add(b, a + n, inf);
        }
        printf("%d
    ", dinic());
        dfs(S);
        int ans = 0;
        for(int i = 0; i < idx; i += 2) {
            int a = e[i ^ 1], b = e[i];
            if(st[a] && !st[b]) {
                ans ++;
            }
        }
        printf("%d
    ", ans);
        for(int i = 0; i < idx; i += 2) {
            int a = e[i ^ 1], b = e[i];
            if(st[a] && !st[b]) {
                if(a == S) printf("%d +
    ", b);
                if(b == T) printf("%d -
    ", a - n);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    Uva 10779 collector's problem
    poj 2728 最优比率树(最小生成树问题)
    LA 3126 二分图匹配 最小路径覆盖
    poj 1149 最大流构图
    Step By Step(Java XML篇)
    Step By Step(Java 输入输出篇)
    Step By Step(Java 集合篇)
    Step By Step(Java 线程篇)
    Step By Step(Java 反射篇)
    Step By Step(Java 国际化篇)
  • 原文地址:https://www.cnblogs.com/miraclepbc/p/14408347.html
Copyright © 2011-2022 走看看