POJ 3469【最小割】

Description
n个任务,两个机器AB,输入n对数字Ai,Bi表示i号任务在A上消耗和在B上的消耗。,然后再给m行,每行a,b,c三个数字,表示如果a任务和b任务不在一个机器上工作的话,需要额外花费c。问所有任务都工作的情况下的最小花费
Input
第一行两个整数N和M表示任务数和约束数,之后N行第i行两个整数Ai和Bi分别表示i任务在机器A和B上的消耗,最后M行每行三个整数a,b,c,表示如果a任务和b任务不在一个机器上工作的话,需要额外花费c
Output
输出所有任务都工作的情况下最小花费。

刚开始看到这个题依然不会建图。。。。然后看到了题解也很懵逼,不明白为什么只要把对应的有限制的点之间连上容量为c的双向边就可以了。。。。
首先是最小割:
为什么是最小割呢?因为从S-T这条路径,代表A,B两种选择都选上,然而我们只有选择其中一种方案就可以了。因此要求割边。
对于有限制的情况:

![](https://images2018.cnblogs.com/blog/1195472/201805/1195472-20180502091621193-434704619.jpg)

当这样连好双向边以后,开始会找到一条S-2-3-T的增广路。还会找到一条S-3-2-T的增广路,这样的结果才是正确的。
如果2-3之间只有单向边,那么S-2-3-T这条路找到以后,就是最优结果,但实际上,1000这个数据是应该加上去的,因为2和3用了不同的core。所以只连单向边是不对的。
个人感觉就是因为在这种图里1000这个值怎样也不会加到结果里,因此1000这条边的存在就是一种限制。
以后想到更好的解释再来补吧。

#include<stdio.h>
#include<string.h>
#include<queue>
#include<iostream>
#define MAX 4000000
#define INF 0x1f1f1f1f
using namespace std;
int ss, tt;
int n, m;
int cont;
int head[MAX];
int divv[MAX];
int cur[MAX];
struct edge {
    int from, to, w, next;

}e[MAX];

void add(int u, int v, int w) {
    e[cont].from = u;
    e[cont].to = v;
    e[cont].w = w;
    e[cont].next = head[u];
    head[u] = cont++;
}



int makediv() {
    memset(divv, 0, sizeof(divv));
    divv[ss] = 1;
    queue<int> Q;
    Q.push(ss);
    while (!Q.empty()) {
        int u = Q.front();
        if (u == tt)
            return 1;
        Q.pop();
        for (int i = head[u]; i != -1; i = e[i].next) {
            int w = e[i].w;
            int v = e[i].to;
            if (divv[v] == 0 && w) {
                divv[v] = divv[u] + 1;
                Q.push(v);
            }
        }

    }
    return 0;

}

int DFS(int u, int maxflow, int tt) {
    if (u == tt)
        return maxflow;
    int ret = 0;
    for (int &i = cur[u]; i != -1; i = e[i].next) {
        int v = e[i].to;
        int w = e[i].w;
        if (divv[v] == divv[u] + 1 && w) {
            int f = DFS(v, min(maxflow - ret, w), tt);
            e[i].w -= f;
            e[i ^ 1].w += f;
            ret += f;
            if (ret == maxflow)
                return ret;

        }
    }
    return ret;
}

void Dinic() {
    int ans = 0;

    while (makediv() == 1) {
        memcpy(cur, head, sizeof(head));
        ans += DFS(ss, INF, tt);
    }

    printf("%d\n", ans);
}


int main(void) {
    while (~scanf("%d%d", &n, &m)) {
        memset(head, -1, sizeof(head));
        cont = 0;
        ss = 0;
        tt = n + 1;
        for (int i = 1; i <= n; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            add(ss, i, u);
            add(i, ss, 0);
            add(i, tt, v);
            add(tt, i, 0);
        }
        int u, v, w;
        for (int i = 1; i <= m; i++) {
            scanf("%d%d%d", &u, &v, &w);
            add(u, v, w);
            add(v, u, w);
        }
        Dinic();

    }


    return 0;


}

猜你喜欢

转载自www.cnblogs.com/tennant/p/8978670.html