http://poj.org/problem?id=3469

poj 3469 Dual Core CPU //最小割(最大流)

poj 3469 Dual Core CPU //最小割(最大流)

题意:求将元素划分成两个集合,元素划分到不同集合有对应的代价,且某两个元素不在同一集合也有代价。

这是一个最小割的问题。(可以用最大流跑出来)

将顶点连接到源点和汇点,并将且某两个元素不在同一集合有代价的元素连接起来。

如图

poj 3469 Dual Core CPU //最小割(最大流)

如果已经划分好两个集合,那么此时的最小割肯定也包含两个集合中间的连接线(当然需要双向边),那么答案就是保证是对的。

最大流跑出最小割就是答案。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<climits>
#include<cmath>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
#define mod 1000000007
#define LL long long
const int max_n = 20010;
struct no{int to,cap,rev;}; //arc
vector<no>g[max_n]; //图
int level[max_n]; //到起点的距离
int iter[max_n]; //当前弧,在其之前的边已经没用了
void addarc(int s,int e,int c){
	g[s].push_back((no){e,c,g[e].size()});
	g[e].push_back((no){s,0,g[s].size()-1});
}
//更新层次,即level
void bfs(int s){
	memset(level,-1,sizeof(level));
	level[s]=0;
	queue<int>q;
	q.push(s);
	while(!q.empty()){
		int now=q.front();q.pop();
		for(int i=0;i<(int)g[now].size();i++){
			no &arc=g[now][i];
			if(level[arc.to]!=-1||arc.cap<=0) continue;
			level[arc.to]=level[now]+1;
			q.push(arc.to);
		}
	}
}
//寻找增广路
int dfs(int v,int t,int f){
	if(v==t) return f;
	for(iter[v];iter[v]<(int)g[v].size();iter[v]++){
		no &arc=g[v][iter[v]];
		if(arc.cap<=0||level[arc.to]!=level[v]+1) continue;
		int d=dfs(arc.to,t,min(f,arc.cap));
		if(d>0) {
			arc.cap=arc.cap-d;
			g[arc.to][arc.rev].cap+=d;
			return d;
		}
	}
	return 0;
}
int Dinic(int s,int t){
	int re=0;
	while(1){
		bfs(s);
		memset(iter,0,sizeof(iter));
		if(level[t]==-1) return re;
		int f;
		while((f=dfs(s,t,INT_MAX))>0)
			re=re+f;
	}
	return re;
}
int main(){
    ios :: sync_with_stdio(false);
	int m,n;
	cin>>n>>m;
	for(int i=1;i<=n;i++){
        int a,b;cin>>a>>b;
        addarc(0,i,a);
        addarc(i,n+1,b);
	}
	for(int i=1;i<=m;i++){
        int a,b,w;cin>>a>>b>>w;
        addarc(b,a,w);
        addarc(a,b,w);
	}
	cout<<Dinic(0,n+1);
    return 0;
}

 

相关文章: