POJ3469 Dual Core CPU(最大流最小割定理)

传送门:http://poj.org/problem?id=3469
题意:有n个点,m条边。有一个双核电脑,对于每个点来说,运行在A核和B核耗费分别是Ai和Bi,然后是m条边,u,v,w。如果u和v在不同的核上运行,就会产生w的耗费。问:最少耗费是多少?
      题目乍看之下很难想到用什么样的思路来做。但是我们可以看出,这题是将n个点分为两部分,一部分在A核,一部分在B核,分为两部分。求两个核的最小耗费,可以看做是求两个核的最小割。因为对于图中的每一个割,都会将源点与汇点分开,其中的顶点,要么属于S集,要么属于T集,跟题意中的分为两个核来处理是一样的意思。显然对于一个割来说,当前割的容量就是当前耗费,要求最小耗费就是求一个最小割,那么我们设立一个源点假设为A核,汇点作为B核。建图,源点跟所有点连接,权值是Ai,所有点跟汇点连接,权值为Bi,再用m条边相互连接双向边。求最大流,就是最小割。
Accepted 6528K 3750MS G++ 2015B

#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<map>
#include<iostream>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<stack>
#include<cctype>
#include<set>
#include<ctime>
#include<cassert>
#include<algorithm>
using namespace std;
typedef long long ll;
const int INF=1e9+7;
typedef pair<int,int> pii;
struct EE{
    int t,v,next;
    EE(){}
    EE(int a,int b,int c):t(a),v(b),next(c){}
}edge[500010];
int head[20010],d[20010];
int n,m,st,ed,Ecnt=0;
inline void add(int s,int t,int v1,int v2){
    edge[Ecnt]=EE(t,v1,head[s]);
    head[s]=Ecnt++;
    edge[Ecnt]=EE(s,v2,head[t]);
    head[t]=Ecnt++;
}
bool BFS(){
    queue<int> Q;
    memset(d,-1,sizeof d);
    d[st]=0;Q.push(st);
    while(!Q.empty()){
        int s=Q.front();Q.pop();
        for(int i=head[s];i!=-1;i=edge[i].next){
            EE e=edge[i];
            if(d[e.t]<0&&e.v>0){
                d[e.t]=d[s]+1;Q.push(e.t);
            }
        }
    }
    return d[ed]>0;
}
int DFS(int s,int t,int flow){
    if(s==t||flow==0)return flow;
    int ans=0;
    for(int i=head[s];i!=-1;i=edge[i].next){
        EE &e=edge[i];
        if(e.v>0&&d[e.t]==d[s]+1){
            int ff=DFS(e.t,t,min(flow,e.v));
            if(ff>0){
                e.v-=ff;
                edge[i^1].v+=ff;
                ans+=ff;
                flow-=ff;
                if(!flow)break;
            }
        }
    }
    if(!ans)d[s]=-1;
    return ans;
}
void dinic(){
    int ans=0;
    while(BFS()){
        ans+=DFS(st,ed,INF);
    }
    printf("%d\n",ans);
}
int main(){
//    freopen("D://input.txt","r",stdin);
    scanf("%d%d",&n,&m);
    st=0;ed=n+1;
    memset(head,-1,sizeof head);
    for(int i=1;i<=n;i++){
        int a,b;scanf("%d%d",&a,&b);
        add(st,i,a,0);
        add(i,ed,b,0);
    }
    for(int i=0;i<m;i++){
        int a,b,c;scanf("%d%d%d",&a,&b,&c);
        add(a,b,c,c);
    }
    dinic();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值