bzoj 1497 最小割

思路:最小割好难想啊,根本想不到。。

S -> 用户群 = c[ i ]

基站 -> T = p[ i ] 

用户群 -> a[ i ] = inf

用户群 -> b[ i ] = inf

然后求最小割,答案就是全部收益的和 - 最小割。

为什么可以这样呢,对于每个用户群,我们可以不选他,就是把(S -> 用户群)这条边断掉,或者选他,就是把

(用户群 -> a[ i ] = inf ,用户群 -> b[ i ] = inf)就是把这两条边断掉。 这样求最小割就能得到答案。

稍微学了一下最大权闭合图, ans =  tot - c (tot 为权值为正的点的和,c 为最小割)。

#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define pii pair<int, int>

using namespace std;

const int N = 6e4 + 7;
const int M = 2e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;

int n, m, S, T, sum, tot, p[N], a, b, c, level[N], head[N];

struct Edge {
    int to, w, nx;
}edge[M << 1];

void add(int u, int v, int w) {
    edge[tot].to = v;
    edge[tot].w = w;
    edge[tot].nx = head[u];
    head[u] = tot++;
}

bool bfs() {
    memset(level, 0, sizeof(level));
    queue<int> que;
    que.push(S), level[S] = 1;

    while(!que.empty()) {
        int u = que.front(); que.pop();
        if(u == T) return true;

        for(int i = head[u]; ~i; i = edge[i].nx) {
            int v = edge[i].to, w = edge[i].w;
            if(level[v] || w <= 0) continue;
            level[v] = level[u] + 1;
            que.push(v);
        }
    }
    return false;
}

int dfs(int u, int p) {
    if(u == T) return p;
    int ret = 0;
    for(int i = head[u]; ~i; i = edge[i].nx) {
        int v = edge[i].to, w = edge[i].w;
        if(level[v] != level[u] + 1 || w <= 0) continue;
        int f = dfs(v, min(p - ret, w));
        ret += f;
        edge[i].w -= f;
        edge[i ^ 1].w += f;
        if(ret == p) break;
    }

    if(!ret) level[u] = 1;
    return ret;
}

int Dinic() {
    int ans = 0;
    while(bfs()) ans += dfs(S, inf);
    return ans;
}

void init() {
    tot = 0; sum = 0;
    memset(head, -1, sizeof(head));
}

int main() {
    init();
    scanf("%d%d", &n, &m);
    S = 0, T = n + m + 1;

    for(int i = 1; i <= n; i++) {
        scanf("%d", &p[i]);
        add(i + m, T, p[i]);
        add(T, i + m, 0);
    }

    for(int i = 1; i <= m; i++) {
        scanf("%d%d%d", &a, &b, &c);
        add(S, i, c), add(i, S, 0);
        add(i, a + m, inf), add(a + m, i, 0);
        add(i, b + m, inf), add(b + m, i, 0);
        sum += c;
    }
    int ans = Dinic();
    printf("%d\n", sum - ans);
    return 0;
}
/*
*/

猜你喜欢

转载自www.cnblogs.com/CJLHY/p/9276305.html