传送门: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;
}