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两种选择都选上,然而我们只有选择其中一种方案就可以了。因此要求割边。
对于有限制的情况:
当这样连好双向边以后,开始会找到一条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;
}