hdu_3081

本文介绍了一种利用二分、最大流算法和并查集处理复杂关系的高效方法,简化了建图过程,特别适用于大规模数据结构问题。通过实例演示,展示了如何在实际应用中优化资源分配和路径查找。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二分+最大流,处理关系的时候使用并查集会比较好,建图简单,忽略
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define MAXVERTEX 	512
#define INF 		0x7fffffff
using namespace std;

typedef struct $edge {
	int x, y;
}Edge;

Edge edge_arr[MAXVERTEX*MAXVERTEX];
int used[MAXVERTEX][MAXVERTEX];
int root[MAXVERTEX], residual[MAXVERTEX][MAXVERTEX], end_vertex;
int pre[MAXVERTEX], cur[MAXVERTEX], dis[MAXVERTEX], gap[MAXVERTEX];

int get_root(int x)
{
	if( x == root[x] )	return x;
	return root[x] = get_root(root[x]);
}

void make_graph(int m, int arc, int vertex)
{
	int f, t;
	memset(residual, 0, sizeof(residual));
	for(int i = 1; i <= vertex; i ++)
		residual[end_vertex-1][i] = m;

	for(int i = vertex+1; i < end_vertex-1; i ++) 
		residual[i][end_vertex] = m;

	for(int i = 0; i < arc; i ++) {
		f = edge_arr[i].x; t = edge_arr[i].y; residual[f][t] = 1;
		for(int j = 1; j <= vertex; j ++) {
			if( root[f] == root[j]) residual[j][t] = 1;
		}
	}
}

int i_sap(int source, int sink)
{
	int u(source), v, min_dist, max_flow(0), path_flow(INF);
	memset(dis, 0, sizeof(dis));
	memset(gap, 0, sizeof(gap));
	memset(cur, 0, sizeof(cur));
	gap[0] = sink; cur[source] = pre[source] = source;

	while( dis[source] < sink ) {
loop:
		for(v = cur[u]; v <= sink; v ++) {
			if( !residual[u][v] || (dis[u] != dis[v]+1) )	continue;
			pre[v] = u; path_flow = min(path_flow, residual[u][v]);
			cur[u] = v; u = v;
			if( v == sink ) {
				for(u = pre[u]; v != source; v = u, u = pre[u]) {
					residual[u][v] -= path_flow;  residual[v][u] += path_flow;
				}
				max_flow += path_flow; path_flow = INF;
			}
			goto loop;
		}

		min_dist = sink;
		for(v = 1; v <= sink; v ++) {
			if( residual[u][v] && (min_dist > dis[v]) ) {
				cur[u] = v; min_dist = dis[v];
			}
		}
		gap[dis[u]] --;
		if( !gap[dis[u]] )	break;
		dis[u] = min_dist+1;
		gap[dis[u]] ++; u = pre[u];
	}
	//printf("max_flow = %d\n", max_flow);
	return max_flow;
}

int main(int argc, char const *argv[])
{
	//freopen("test.in", "r", stdin);
	int cnt, vertex, arc, match, l, r, m, x, y, r_x, r_y, ans;
	scanf("%d", &cnt);
	while( cnt-- ) {
		scanf("%d %d %d", &vertex, &arc, &match);
		end_vertex = (vertex<<1)+2;
		for(int i = 0; i < arc; i ++) {
			scanf("%d %d", &edge_arr[i].x, &edge_arr[i].y);
			edge_arr[i].y += vertex;
		}

		for(int i = 0; i <= end_vertex; i ++)
			root[i] = i;

		for(int i = 0; i < match; i ++) {
			scanf("%d %d", &x, &y);
			r_x = get_root(x); r_y = get_root(y);
			if( r_x != r_y ) root[r_x] = r_y;
		}

		for(int i = 0; i <= end_vertex; i ++)
			root[i] = get_root(i);

		l = 1, r = vertex, ans = 0;
		while( l <= r ) {
			m = (l+r)>>1; make_graph(m, arc, vertex);
			if( m*vertex == i_sap(end_vertex-1, end_vertex) )	{
				ans = m; l = m+1;
			}
			else
				r = m-1;
		}
		printf("%d\n", ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值