POJ 2112Optimal Milking 最大流

Dinic算法详解
本文介绍了一种高效的网络流算法——Dinic算法,并通过一个具体的实现案例进行了解析。该算法适用于寻找最大流问题,在图论中有着广泛的应用。文章详细展示了Dinic算法的数据结构定义、初始化过程、增广路径搜索及流量更新等核心步骤。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;

#define mxn 402
#define inf 0x3f3f3f3f
#define mxe 50020

struct edge {
	int u, v, cap, flow, nxt;
	edge() {}
	edge( int u, int v, int cap, int flow, int nxt ):
		u( u ), v( v ), cap( cap ), flow( flow ), nxt( nxt ) {}
};
struct dinic {
	int s, t, cc;
	int cur[mxn], d[mxn];
	int fst[mxn];
	edge e[mxe];

	void init() {
		memset( fst, -1, sizeof( fst ) );
		cc = 0;
	}
	void add( int u, int v, int cap ) {
		e[cc] = edge( u, v, cap, 0, fst[u] );
		fst[u] = cc++;
		e[cc] = edge( v, u, 0, 0, fst[v] );
		fst[v] = cc++;
	}
	bool bfs() {
		memset( d, -1, sizeof( d ) );
		queue<int> q;
		d[s] = 0;
		q.push( s );
		while( !q.empty() ) { 
			int x = q.front(); q.pop();
			for( int i = fst[x]; ~i; i = e[i].nxt ) {
				int v = e[i].v;
				if( d[v] == -1 && e[i].cap > e[i].flow ) {
					d[v] = d[x] + 1;
					q.push( v );
				}
			}
		}
		return ~d[t];
	}
	int dfs( int x, int a ) {
		if( x == t || a == 0 )
			return a;
		int flow = 0, f;
		for( int& i = cur[x]; ~i; i = e[i].nxt ) {
			if( i == inf )
				i = fst[x];
			if( i == -1 )
				break;
			int v = e[i].v;
			if( d[v] == d[x] + 1 && ( f = dfs( v, min( a, e[i].cap - e[i].flow ) ) ) > 0 ) {
				a -= f;
				e[i].flow += f;
				e[i^1].flow -= f;
				flow += f;
				if( !a )
					break;
			}
		}
		return flow;
	}
	int go( int s, int t ) {
		this -> s = s, this -> t = t;
		int flow = 0;
		while( bfs() ) {
			memset( cur, 0x3f, sizeof( cur ) );
			flow += dfs( s, inf );
		}
		return flow;
	}
}go;

int n, C, m;
int d[mxn][mxn];
int S, T;

void read() {
	for( int i = 1; i <= n + C; ++i ) {
		for( int j = 1; j <= n + C; ++j ) {
			scanf( "%d", &d[i][j] );
			if( d[i][j] == 0 && i != j )
				d[i][j] = inf;
		}
	}
	for( int k = 1; k <= n + C; ++k )
		for( int i = 1; i <= n + C; ++i )
			for( int j = 1; j <= n + C; ++j )
				d[i][j] = min( d[i][k] + d[k][j], d[i][j] );
}
int main() {
	while( scanf( "%d%d%d", &n, &C, &m ) != EOF ) {
		read();
		S = 0, T = n + C + 1;
		int head = 0, tail = inf;
		while( head < tail ) {
			go.init();
			int mid = ( head + tail ) / 2;
			for( int i = 1; i <= n; ++i ) {
				for( int j = n + 1; j <= n + C; ++j )
					if( d[i][j] <= mid )
						go.add( i, j, 1 );
				go.add( S, i, m );
			}
			for( int i = n + 1; i <= n + C; ++i )
				go.add( i, T, 1 );
			if( go.go( S, T ) == C )
				tail = mid;
			else
				head = mid + 1;
		}
		printf( "%d\n", head );
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值