Poj 3469 Dual Core CPU(最小割)

Poj 3469 Dual Core CPU

题目描述

Dual Core CPU
Time Limit: 15000MS
Memory Limit: 131072K
Total Submissions: 28432

Description
As more and more computers are equipped with dual core CPU, SetagLilb, the Chief Technology Officer of TinySoft Corporation, decided to update their famous product - SWODNIW.
The routine consists of N modules, and each of them should run in a certain core. The costs for all the routines to execute on two cores has been estimated. Let’s define them as Ai and Bi. Meanwhile, M pairs of modules need to do some data-exchange. If they are running on the same core, then the cost of this action can be ignored. Otherwise, some extra cost are needed. You should arrange wisely to minimize the total cost.

Input
There are two integers in the first line of input data, N and M (1 ≤ N ≤ 20000, 1 ≤ M ≤ 200000) .
The next N lines, each contains two integer, Ai and Bi.
In the following M lines, each contains three integers: a, b, w. The meaning is that if module a and module b don’t execute on the same core, you should pay extra w dollars for the data-exchange between them.

Output
Output only one integer, the minimum total cost.

Sample Input
3 1
1 10
2 10
10 3
2 3 1000
Sample Output
13

题解

由《挑战程序设计》P236页。
思路:先转换为求最小割问题;再利用网络中最小割等于最大流求解。
一般将对象划分为两个集合的问题,可以使用最小割分隔。

设在核A上工作的模块集合为S,在核B上工作的集合为T;
所要求的花费为:
sum{A[i]|i属于S}+sum{B[i]|i属于T}+
sum{w[i]|(a[i]属于S,b[i]属于T)或(a[i]属于T,b[i]属于S)}
可以适当建边使得花费等价于割的容量。

  1. 对于sum{A[i]|i属于S},可以对每个模块向汇点t连边;切割时在S的模块到t的边都在割上。
  2. 对于sum{B[i]|i属于T},可以源点s向每个模块连边;
  3. 对于sum{w[i]|(a[i]属于S,b[i]属于T)或(a[i]属于T,b[i]属于S)},可以对每个w[i],在a[i]和b[i]间相互连边。

故只要求出网络的最小割即可。
由于最大流=最小割,所以跑最大流算法。

代码

#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;

typedef long long ll;
const int maxn=2e5+5;
const int INF=0x3f3f3f3f;
const int inf=0x3f;
class Edge{
public:
	int to,cap,nxt,rev;
};
int head[maxn],cur[maxn];
Edge edge[maxn<<4];
int cnt=1;
int N,M,S,T;

int level[maxn];

void add(int u,int v, int cap){
	edge[cnt].to=v;edge[cnt].cap=cap;edge[cnt].nxt=head[u];edge[cnt].rev=cnt+1; head[u]=cnt++;
	edge[cnt].to=u;edge[cnt].cap=0; edge[cnt].nxt=head[v];edge[cnt].rev=cnt-1; head[v]=cnt++;
}
void init(){
	memset(head,0,sizeof(head));
	memset(edge,0,sizeof(edge));
	cnt=1;
}

void bfs(){
	memset(level,-1,sizeof(level));
	level[S]=0;
	queue<int> que;
	que.push(S);
	while(!que.empty()){
		int now=que.front(); que.pop();
		for(int i=head[now];i;i=edge[i].nxt){
			Edge &e=edge[i];
			if(level[e.to]<0&&e.cap>0){
				level[e.to]=level[now]+1;
				que.push(e.to);
			}
		}
	}
}
int dfs(int now,int flow){
	if(now==T) return flow;
	for(int i=cur[now];i;i=edge[i].nxt){
		cur[now]=i;
		Edge &e=edge[i];
		if(level[e.to]>level[now]&&e.cap>0){
			int d=dfs(e.to, min(flow, e.cap));
			if(d>0){
				e.cap-=d;
				edge[e.rev].cap+=d;
				return d;
			}
		}
	}
}
void Dinic(){
	int res=0;
	for(;;){
		bfs();
		if(level[T]<0) break;
		for(int i=1;i<=T;i++) cur[i]=head[i];
		int d;
		while(d=dfs(S,INF)){
			res+=d;
		}
	}
	printf("%d\n",res);
}
int main(){
	int A,B,u,v,w;
	while(~scanf("%d%d",&N,&M)){
		init();
		S=N+1;T=N+2;
		for(int i=1;i<=N;i++){
			scanf("%d%d",&A,&B);
			add(S,i,B);add(i,T,A);
		}
		for(int i=1;i<=M;i++){
			scanf("%d%d%d",&u,&v,&w);
			add(u,v,w); add(v,u,w);
		}
		Dinic();
	}
} 

第一次理解最小割==最大流 这条性质的用处。对于分割两种集合最小耗费的问题有了新的思路~还要继续学习啊

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值