(Great!)poj3469 Dual Core CPU
最小割
复杂度:dinic,能跑1e4到1e5的网络,理论复杂度\((n^2m)\)
求将对象划分为两个集合的最小费用常用最小割,但此题难点在于建图
- 因为每个模块要么在A,要么在B,故向S,T连边,对每个点必须割掉一条边,不多不少,正符合最小割的条件——整张图都不联通,且不割多余的边
- 又因为若A,B属于两个集合且A,B有边,需要割掉A,B间的边,才能保证S和T不联通,这也正是题目所要求的
#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
using namespace std;
#define go(i,a,b) for(int i=a;i<=b;++i)
#define com(i,a,b) for(int i=a;i>=b;--i)
#define mem(a,b) memset(a,b,sizeof(a))
#define add_e(u,v,w) add(u,v,w),add(v,u,0)
const int inf=0x3f3f3f3f,N=20000+10,s=0,t=20001;
int n,m,cnt=0,head[N],d[N];
struct edge{
int nxt,v,w;
}e[N*50];
queue<int>q;
void add(int u,int v,int w){
e[cnt]=(edge){head[u],v,w};
head[u]=cnt++;
}
inline void read(int &x){
x=0;char f=1,c=getchar();
while(!isdigit(c)){ if(c=='-') f=-1; c=getchar(); }
while(isdigit(c)){ x=x*10+c-'0'; c=getchar(); }
x*=f;
}
bool bfs(){
while(!q.empty()) q.pop();
mem(d,0);
d[s]=1;q.push(s);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u];i+1;i=e[i].nxt){
int v=e[i].v;
if(!e[i].w||d[v]) continue;
d[v]=d[u]+1;
if(v==t) return 1;
q.push(v);
}
}
return 0;
}
int dinic(int u,int low){
if(u==t) return low;
int res=low,f;
for(int i=head[u];i+1&&res;i=e[i].nxt){
int v=e[i].v;
if(d[v]==d[u]+1&&e[i].w){
f=dinic(v,min(res,e[i].w));
if(!f) d[v]=0;
e[i].w-=f;e[i^1].w+=f;
res-=f;
}
}
return low-res;
}
int main(){
mem(head,-1);
//freopen("input.txt","r",stdin);
read(n),read(m);
int x,y,w;
go(i,1,n){
read(x),read(y);
add_e(s,i,x);
add_e(i,t,y);
}
go(i,1,m){
read(x),read(y),read(w);
add_e(x,y,w);
add_e(y,x,w);
}
int ans=0;
while(bfs()) ans+=dinic(s,inf);
cout<<ans;
return 0;
}