 /**//*
點(diǎn)權(quán)一般變?yōu)檫厵?quán)
這里轉(zhuǎn)化為求最小割

題意:有一些模塊(modules)和一個雙核處理器,一個模塊可以在任意一個核上處理,每個核對應(yīng)每個模塊有個開銷。
現(xiàn)在有一些模塊間需要數(shù)據(jù)交換,如果需要數(shù)據(jù)交換的模塊在一個核上處理,則不需要額外開銷,否則需要加上一個開銷。
現(xiàn)在需要完成所有模塊,問最小需要多少開銷。
如果沒有這個額外的開銷,那么每個模塊只要選擇開銷小的那個核就行了。額外的開銷給選擇加上了限制。

網(wǎng)絡(luò)流的模型:
每個模塊一個節(jié)點(diǎn),原點(diǎn)與所有模塊節(jié)點(diǎn)連接(稱為上邊),邊權(quán)為第一個核對應(yīng)該模塊的開銷。
所有模塊節(jié)點(diǎn)連接到匯點(diǎn)(稱為下邊),權(quán)為第二個核對應(yīng)該模塊的開銷。
然后需要數(shù)據(jù)交換的兩個模塊結(jié)點(diǎn)之間連接雙向邊(兩個單向邊,稱為中邊),權(quán)為對應(yīng)的那個額外開銷。

這樣,該圖的最小割中,原點(diǎn)和模塊節(jié)點(diǎn)之間的邊,或者模塊節(jié)點(diǎn)與匯點(diǎn)之間的邊至少一條在割之中。
同時,如果數(shù)據(jù)交換的結(jié)點(diǎn)選擇了不同的核,那么他們之間的中邊一定也在割集中 (如果不在,那么可以構(gòu)造出更小的割)。
如果選擇了相同的核,那么模塊節(jié)點(diǎn)之間的那條表一定在割之中模塊節(jié)點(diǎn)之間的那條表一定不在割之中(因?yàn)槭亲钚「睿?br>

http://blog.csdn.net/biran007/archive/2009/05/26/4218454.aspx
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int MAXN = 20000;
const int INF = 1000000000;

struct Edge
  {
int v,cap;
Edge *next,*pair;
}edge[MAXN*22*2+10];

struct Graph
  {
Edge *G[MAXN+10],*cur[MAXN+10],*pE;
int dist[MAXN+10],num[MAXN+10];
int n,s,t;
void init(int nn,int ss,int tt)
 {
n=nn;
s=ss,t=tt;
memset(G,0,sizeof(G));
pE=edge;
}
void add(int u,int v,int cap,Edge *pair)
 {
pE->v=v;
pE->cap=cap;
pE->next=G[u];
pE->pair=pair;
G[u]=pE++;
}
void add(int u,int v,int cap)
 {
add(u,v,cap,pE+1);
add(v,u,0,pE-1);
}
int aug(int u,int preCap)
 {
if(u==t)return preCap;
int leftCap=preCap;
for(Edge *&it=cur[u];it;it=it->next)
 {
if(it->cap&&dist[it->v]+1==dist[u])
 {
int d=aug(it->v,min(leftCap,it->cap));
it->cap-=d;
it->pair->cap+=d;
leftCap-=d;
if(leftCap==0||dist[s]==n)return preCap-leftCap;
}
}

int minDist=n;
for(Edge *it=cur[u]=G[u];it;it=it->next)
if(it->cap)minDist=min(minDist,dist[it->v]+1);//+1
if(--num[dist[u]]==0)dist[s]=n;
else num[dist[u]=minDist]++;
return preCap-leftCap;
}
int maxFlow()
 {
memset(dist,0,sizeof(dist));
memset(num,0,sizeof(num));
memmove(cur,G,sizeof(G));
num[0]=n;
int flow=0;
while(dist[s]<n)flow+=aug(s,INF);
return flow;
}
}graph;
int main()
  {
int n,m,a,b,c;
while(~scanf("%d%d",&n,&m))
 {
graph.init(n+2,0,n+1);
for(int i=1;i<=n;i++)
 {
scanf("%d%d",&a,&b);
graph.add(0,i,a);
graph.add(i,n+1,b);
}
for(int i=0;i<m;i++)
 {
scanf("%d%d%d",&a,&b,&c);
graph.add(a,b,c);
graph.add(b,a,c);
}
printf("%d\n",graph.maxFlow());
}
return 0;
}
|