【poj 3469 】 Dual Core CPU 【最大流+最小割建图】

Dual Core CPU
Time Limit: 15000MS Memory Limit: 131072K
Total Submissions: 20854 Accepted: 9011
Case Time Limit: 5000MS
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

题意:由于越来越多的计算机配置了双核CPU,TinySoft公司的首席技术官员,SetagLilb,决定升级他们的产品-SWODNIW。SWODNIW包含了N个模块,每个模块必须运行在某一个CPU中。每个模块在每个CPU中运行的耗费已经被估算出来了,设为Ai和Bi。同时,M对模块之间需要共享数据,如果他们运行在同一个CPU中,共享数据的耗费可以忽略不计,否则,还需要额外的费用。你必须很好地安排这N个模块,使得总耗费最小。

白书上例题第236页
用最小的费用将对象划分位两个集合的问题,常常可以转化成最小割后解决。
最小割: 就是去掉一些边,然后使S和T不会连通,同时让去掉的边的容量和最小。
本题也是 用最小的费用将N个模块分为给两个cpu。
我们可以将第一个CPU 化为超级远点S,
…………..将第二个CPU 化为超级汇点T;
我直接建好图 来说一下我的理解吧 (可能不一定对)我以两个模块为例子来建图。
这里写图片描述
A与B模块之间是有共享的,边的容量为不同cpu的时候多花费的钱。
S与A和B的连边容量为单独在第一个CUP中所花费的钱。
T 与A和B的连边容量为单独在第二个CPU中所花费的钱。

我们现在想求最小割,先来找一下,所有的能够割断这个图的情况。
1 > . 断1 和 2 边
2 > 断 3 和 4 边
3 > 断1 和 6 和 4 边
4 > 断 2 和 5 和 3 边
情况1 和2 的割时候其实就是将AB都分到同一个CPU中,此时没有额外花费
情况3 和4 的割时候其实就是将AB不分到同一个CPU中,这种情况也符合题意,如果不在同一个CPU必定会有额外的花费。
这时候我们取这个四个割的最小,不就是我们想要的 答案。

如果我理解的有误,欢迎指出!!
代码

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
#define  LL long long
#define fread() freopen("in.txt","r",stdin)
#define fwrite() freopen("out.txt","w",stdout)

const int MAXN = 20000+100   ;
const int MAXM =1000000+10 ;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;

struct Edge {
    int form,to,cap,flow,nexts;
}edge[MAXM];
int head[MAXN],top;
void init(){
    memset(head,-1,sizeof(head));
    top=0;
}
void addedge(int a,int b,int c){
    Edge e={a,b,c,0,head[a]};
    edge[top]=e;head[a]=top++;

    Edge ee={b,a,0,0,head[b]};
    edge[top]=ee;head[b]=top++;
}

int S,T;
int n,m;
void getmap(){
    S=0;T=n+1;
    for(int i=1;i<=n;i++){
        int a,b;scanf("%d%d",&a,&b);
        addedge(S,i,a);
        addedge(i,T,b);
    }
    while(m--){
        int a,b,c;scanf("%d%d%d",&a,&b,&c);
        addedge(a,b,c);
        addedge(b,a,c);
    }
}
int vis[MAXN],dis[MAXN];
int cur[MAXN];
bool bfs(int st,int ed){
    queue<int>Q;
    memset(vis,0,sizeof(vis));
    memset(dis,-1,sizeof(dis));
    Q.push(st);vis[st]=1;dis[st]=1;
    while(!Q.empty()){
        int now=Q.front();Q.pop();
        for(int i=head[now];i!=-1;i=edge[i].nexts){
            Edge e=edge[i];
            if(!vis[e.to]&&e.cap-e.flow>0){
                vis[e.to]=1;
                dis[e.to]=dis[now]+1;
                if(e.to==ed) return 1;
                Q.push(e.to);
            }
        }
    }
    return 0;
}
int dfs(int now,int a,int ed){
    if(a==0||now==ed) return a;
    int flow=0,f;
    for(int &i=cur[now];i!=-1;i=edge[i].nexts){
        Edge &e=edge[i];
        if(dis[e.to]==dis[now]+1&&(f=dfs(e.to,min(e.cap-e.flow,a),ed))>0){
            e.flow+=f;
            flow+=f;
            edge[i^1].flow-=f;
            a-=f;
            if(a==0) break;
        } 
    }
    return flow;
}
int max_flow(int st ,int ed){
    int flow=0;
    while(bfs(st,ed)){
        memcpy(cur,head,sizeof(head));
        flow+=dfs(st,inf,ed);
    }
    return flow;
}

int main(){  
//  fread();
//  fwrite();
    while(scanf("%d%d",&n,&m)!=EOF){
        init();
        getmap();
        int ans=max_flow(S,T);
        printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值