http://poj.org/problem?id=3469
题意:要在核A与核B组成的双核cpu上面运行n个模块,给出每个模块在核A、核B上运行的时间。除此之外,接下来还有m组需要交换数据的模块。每当两组模块在一个核上运行时,不需要任何的额外花费,反之需要一定的额外花费。求运行完n个模块所需的最少时间。
这个最小割不是很好理解 我也说不太清楚,看这位大佬的博客吧https://blog.csdn.net/flynn_curry/article/details/52975190
难点是模型转换,建图
我的理解就是 最小割就是你让一个连通图变得不连通的最小花费(不是费用流哦),即割边(删边)的最小代价。
最小割即最大流(定理)
最小割模型:
网络流最小割
这道题的本质就是求一个分组方案,在核A上面运行一组,在核B上面运行为一组。然后求其最小花费。所以可以转换为一个最小割 像这种用最小的费用将对象划分成两个集合的问题,常常可以转换成最小割后顺利解决。
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<stdlib.h>
#include<queue>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1000000;
typedef long long LL;
const int N = 20005;
const int INF = 0x3f3f3f3f;
bool vis[N];
struct Edge{
int to, cap, flow, next;
}edge[N*50];
int n, m, cnt;//n是点 m是边 cnt是加边操作后的边
int head[N];//邻接表
int dis[N];//分层 等级
int cur[N];//弧优化
void add(int u, int v, int w){
edge[cnt] = (struct Edge){v, w, 0, head[u]};
head[u] = cnt++;
edge[cnt] = (struct Edge){u, 0, 0, head[v]};
head[v] = cnt++;
}
bool bfs(int start, int endd){//分层
memset(dis, -1, sizeof(dis));
memset(vis, false, sizeof(vis));
queue<int>que;
dis[start] = 0;
vis[start] = true;
que.push(start);
while(!que.empty()){
int u = que.front();
que.pop();
for(int i = head[u]; i != -1; i = edge[i].next){
Edge E = edge[i];
if(!vis[E.to] && E.flow<E.cap){
dis[E.to] = dis[u]+1;
vis[E.to] = true;
if(E.to == endd) return true;
que.push(E.to);
}
}
}
return false;
}
int dfs(int x, int res, int endd){ //增广
if(x == endd || res == 0) return res;
int flow = 0, f;
for(int& i = cur[x]; i != -1; i = edge[i].next){
Edge E = edge[i];
if(dis[E.to] == dis[x]+1){
f = dfs(E.to, min(res, E.cap-E.flow), endd);
if(f>0){
edge[i].flow += f;
edge[i^1].flow -= f;
flow += f;
res -= f;
if(res == 0) break;
}
}
}
return flow;
}
int max_flow(int start, int endd){
int flow = 0;
while(bfs(start, endd)){
memcpy(cur, head, sizeof(head));//初始化弧优化数组
flow += dfs(start, INF, endd);
}
return flow;
}
void init(){//初始化
cnt = 0;
memset(head, -1, sizeof(head));
}
int main(){
scanf("%d%d", &n, &m);
init();
int sp=0;//建立超级源点
int tp=n+1;//超级汇点
for(int i = 1; i <= n; i++){
int x,y;
scanf("%d%d",&x,&y);
add(sp, i, x);
add(i, tp, y);
}
for(int i = 1; i <= m; i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x, y, z);
add(y, x, z);//注意 加的该边为双向边
}
int ans = max_flow(sp, tp);
printf("%d\n", ans);
return 0;
}