您的位置:首页 > 其它

Poj 3469 Dual Core CPU(最小割)

2020-07-02 22:11 15 查看

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();
}
}

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: