BZOJ 1497 最大获利 【最大权闭合子图】

传送门
题意: 建立一些基站有费用, 然后有m个连接关系, 那就是第i个人需要使用ai, bi 基站进行通信, 同时公司有ci的获利, 问公司最大获利是多少.

思路: 很明显的依赖关系, 基站为点, 人也为点, 如果需要ai, bi, 基站, 那就向对应基站连边即可, 所以就是很明显的最大权闭合子图. 建出相应的模型, 然后用网络流求解即可.

AC Code

const int maxn = 6e4 + 5;
int cnt ;
int n, m, s, t;
bool vis[maxn];
int d[maxn], cur[maxn];
struct Edge {
    int u, v;
    int cap, flow;
} e[maxn*10];    //因为是双向边  所以记得开二倍
vector<int> G[maxn];
void init() {
    cnt = 0;
    for (int i = 1 ; i <= n ; i ++) G[i].clear();
}

void add(int u, int v, int cap, int f) {
    e[cnt] = Edge{u, v, cap, f};
}

void AddEdge(int u, int v, int cap) {
    add(u, v, cap, 0);
    G[u].push_back(cnt++);
    add(v, u, 0, 0);
    G[v].push_back(cnt++);
}

bool BFS() {
    Fill(vis, 0);
    queue<int> q; q.push(s);
    vis[s] = 1; d[s] = 0;
    while (!q.empty()) {
        int v = q.front(); q.pop();
        for (int i = 0; i < G[v].size(); i++) {
            Edge &te = e[G[v][i]];
            if (!vis[te.v] && te.cap > te.flow) { //只考虑残量网络的弧
                vis[te.v] = 1;
                d[te.v] = d[v] + 1;
                q.push(te.v);
            }
        }
    }
    return vis[t];
}

int dfs(int x, int a) {
    if (x == t || a == 0) return a;
    int flow = 0, f;
    for (int &i = cur[x]; i < G[x].size(); i++) { //从上次考虑的弧
        Edge &te = e[G[x][i]];
        if (d[x] + 1 == d[te.v] && (f = dfs(te.v, min(a, te.cap - te.flow))) > 0) {
            te.flow += f;
            e[G[x][i]^1].flow -= f;
            flow += f;
            a -= f;
            if (a == 0) break;
        }
    }
    return flow;
}

int Dinic() {
    int flow = 0;
    while (BFS()) {
        Fill(cur, 0);
        flow += dfs(s, inf);
    }
    return flow;
}

void solve() {
    scanf("%d%d", &n, &m);
    init(); s = 0, t = n + m  + 1;
    for (int i = 1 ; i <= n ; i ++) {
        int x; scanf("%d", &x);
        AddEdge(i, t, x);
    }
    int ans = 0;
    for (int i = 1 ; i <= m ; i ++) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        AddEdge(i+n, u, w);
        AddEdge(i+n, v, w);
        AddEdge(s, i+n, w);
        ans += w;
    }
    printf("%d\n", ans - Dinic());
}

猜你喜欢

转载自blog.csdn.net/anxdada/article/details/80259422
今日推荐