POJ-3469 Dual Core CPU 最小割最大流
该题是给定对个任务,然后告诉你这多个任务在两个不同的核心上执行任务所花费的不同代价,并且还告诉如果其中一些任务不在同一个核心上面运行的话,还有有多余的开销。最后问我们完成所有任务的最小开销是多少?
对于这个问题,我们先把问题简单话一下,如果没有第二个约束条件,仅仅只有在两个核上的运行时间。那么可能你会说对每个时间所花费的时间取一个最小值就可以了,事实也确实如此,但是如果用流网络来建立这个模型的话,那么我们需要将这个事件拆成两个点,从源点流向左边点的容量是一个核心上花费的时间,两个事件点之间的容量为无穷大,右边点流向汇点的容量为该事件在第二个核心上面所花费的时间,由于中间的边的容量是无穷大,所以最小割的边集中一定没有这些边,也因此这样选择出来的最小割就是我们所要的答案。
让我们再将这个问题的难度加大,也即附上题目中所给定的约束,两个事件在不同的核心上处理将带来多余的时间开销,假设输入数据为A, B, T 表示A事件与B事件不再同一核心上面的要多花费T时间,那么我们为一个事件再添加两条路径(用 A, A' 表示左右两个事件点),从 A -(T)-> B -(INF)->A' 以及 B -(T)-> A -(INF)->B',这样相当与给了整个时间更多的选择,此时求出来的最小割即为我们想要的最小值。
代码如下:
#include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm> #include <queue> #define RE(x) ((x)^1) #define CP(x) ((x)+20000) #define INF 0x3fffffff using namespace std; int N, M, dis[40005], idx = -1, head[40005]; const int source = 0, sink = 40001; struct Edge { int v, cap, next; }e[1000000]; // 100万条边 void insert(int a, int b, int c) { ++idx; e[idx].v = b, e[idx].cap = c; e[idx].next = head[a], head[a] = idx; } bool bfs() { int u; queue<int>q; memset(dis, 0xff, sizeof (dis)); dis[source] = 0; q.push(source); while (!q.empty()) { u = q.front(); q.pop(); for (int i = head[u]; i != -1; i = e[i].next) { if (dis[e[i].v] == -1 && e[i].cap > 0) { dis[e[i].v] = dis[u] + 1; q.push(e[i].v); } } } return dis[sink] != -1; } int dfs(int u, int flow) { if (u == sink) { return flow; } int tf = 0, sf; for (int i = head[u]; i != -1; i = e[i].next) { if (dis[u]+1 == dis[e[i].v] && e[i].cap > 0 && (sf = dfs(e[i].v, min(flow-tf, e[i].cap)))) { e[i].cap -= sf, e[RE(i)].cap += sf; tf += sf; if (tf == flow) { return flow; } } } if (!tf) { dis[u] = -1; // 剪枝 } return tf; } int dinic() { int ans = 0; while (bfs()) { ans += dfs(source, INF); } return ans; } int main() { int a, b, c; memset(head, 0xff, sizeof (head)); scanf("%d %d", &N, &M); for (int i = 1; i <= N; ++i) { scanf("%d %d", &a, &b); insert(source, i, a); insert(i, source, 0); insert(i, CP(i), INF); insert(CP(i), i, 0); insert(CP(i), sink, b); insert(sink, CP(i), 0); } for (int i = 1; i <= M; ++i) { scanf("%d %d %d", &a, &b, &c); insert(a, b, c); insert(b, a, c); insert(a, CP(b), INF); insert(b, CP(a), INF); } printf("%d\n", dinic()); return 0; }