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