POJ_3469 Dual Core CPU 最大流

http://poj.org/problem?id=3469

题意:

有N项工作需要用CPU执行完成,现在只有2个CPU,已知每个项任务在两个CPU上

的执行时间,并且还给出了一些约束条件,每个约束条件是:(u , v  , c)表示如果任务

u和v不在同一个机器上执行的话,就需要付出额外的c的代价,求完全任务的最少花

费是多少。

思路:

首先每项任务都需要完成,而且每项任务都只能在一台机器上完成,这不免会让人想

到是否可以用2-sat,但是问题是题目中并没有给没有给出两个不能在同一台机器上, 

而是给出了两个任务不在同一台机器上的代价,没有“冲突”,因此我们不能用2-sat解决。

然后就是考虑到每个任务只要在A机器或是B机器上完成,也就是说我们只需要确定一种

方案将所有任务分别分在A或是B上就可以了,这样我们就会想到最大流最小割定理,可

以利用求最大流来求出图的最小割,从而求解本题。建图的原则是,引入一个超级源点

和超级汇点,从源点引一条边到每个点,代价为该点在机器A上执行的时间,从每个点引

一条边到汇点,代价为该点在机器B上执行的时间,对于题目中给出的约束(u , v ,c )添加

一条总u到v的代价为c的边和 v到u的代价为c的边,最后跑一次最大流的sap算法就可以出解。


代码:

#include<stdio.h>
#include<string.h>
#define MIN(a,b) (a)>(b)?(b):(a)
#define CC(m ,what) memset(m , (what) , sizeof(m))
#define FF(i , CH) for(int i=0;i<CH;i++)

int N ,M ,S,T;
const int MAX_E = 600000 ;
const int MAXN = 20020 ;
const int inf = (1<<30) ;

struct Node{
    int num ,dis ,next;
}p[MAX_E*2] ;
int root[MAXN] ,cnt,nodenum;

void init(){
    memset(root, -1 , sizeof(root));
    cnt = 0 ; S = 0 ; T = N + 1 ;
}
void add(int a , int b , int c ,int cc=0){
    p[cnt].num = b ;
    p[cnt].dis = c ;
    p[cnt].next = root[a] ;
    root[a] = cnt++ ;
    p[cnt].num = a ;
    p[cnt].dis = cc ;
    p[cnt].next = root[b] ;
    root[b] = cnt++ ;
}
int dis[MAXN] , gap[MAXN] , cur[MAXN] , pre[MAXN];
/*
用领接矩阵实现的SAP
dis[i]: 层次图中点i到T的距离
cur[i]: i结点当前出去的边的编号
pre[i]: i结点的前一个结点
*/
void checkmin(int &a , int b){
    a = a > b ? b : a ;
}
void sap(){
    CC(dis,  0); CC(gap , 0) ;
    FF(i , nodenum)     cur[i] = root[i] ;
    int u = pre[S] = S ,max_flow = 0 , aug = inf ;
    gap[0] = nodenum ;

    while( dis[S] < nodenum){
loop :
            for(int &i=cur[u] ;i!=-1;i=p[i].next){
                int v = p[i].num ;
                if( p[i].dis && dis[u] == dis[v] + 1){
                        checkmin( aug , p[i].dis ) ;
                        pre[ v ] = u ; u = v ;
                        if(v == T){
                                max_flow += aug ;
                                for(u = pre[u] ; v != S ; v=u,u=pre[u]){
                                    p[ cur[u] ].dis -= aug ;
                                    p[ cur[u]^1 ].dis += aug ;
                                }
                                aug = inf ;
                        }
                        goto loop ;
                }
            }
            int mind = nodenum  ;
            for(int i=root[u] ;i!=-1;i=p[i].next){
                int v = p[i].num ;
                if( p[i].dis && mind > dis[v] ){
                    mind = dis[v] ;
                    cur[u] = i ;
                }
            }
            if( (--gap[ dis[u] ])==0)   break ;
            gap[ dis[u] = mind + 1 ]++ ;
            u = pre[u] ;
    }
    printf("%d\n",max_flow) ;
}

int main(){
    int a, b ,c;
    while(scanf("%d%d",&N,&M) == 2){
        init() ;
        for(int i=1;i<=N;i++){
            scanf("%d%d",&a,&b);
            add(S,i,a); add(i,T,b);
        }
        for(int i=1;i<=M;i++){
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c,c) ;
        }
        nodenum = N + 2 ;
        sap() ;
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值