POJ 1087 A Plug for UNIX (最大流,EK算法)

题意:读题很恶心···。大概就是说现在有n个不同的插孔,m台不同的用电器,k种适配器。(适配器就相当于一个中间插座,比如一个适配器是(x,y)。有一台用电器必须插x插孔,但是现在只有一个y插孔,那么就可以通过适配器来连接)。另外需要注意的就是给出的是适配器的种数,每一种的数量无限制。
题解:建图的大概思路。s-->电器-->适配器-->插孔-->t

#include <queue>
#include <cstring>
#include <iostream>
using namespace std;

#define N 101
#define INF 9999

char recep[N][25];
char device[N][25];

struct Item
{
	char in[25];
	char out[25];
} adapt[N];

bool vis[N*3];
int pre[N*3];
int cap[N*3][N*3];
int flow[N*3][N*3];
int n, m, k;
int s, t, res;

void build_map()
{
	s = 0;
	t = n + m + k + 1;
	memset(cap,0,sizeof(cap));

	int i, j;
	for ( i = 1; i <= m; i++ )
	{
		cap[s][i] = 1;  // s到电器

		for ( j = 1; j <= n; j++ ) //电器到插孔
			if ( ! strcmp(device[i],recep[j]) )
				cap[i][j+m+k] = 1;

		for ( j = 1; j <= k; j++ )  //电器到适配器
			if ( ! strcmp(device[i],adapt[j].in) )
				cap[i][j+m] = 1;
	}

	for ( i = 1; i <= k; i++ )
	{
		for ( j = 1; j <= k; j++ )  // 适配器之间联系
		    if ( i != j && !strcmp(adapt[i].out, adapt[j].in) )
				cap[i+m][j+m] = INF;   // 数量不限制,所以是INF

		for ( j = 1; j <= n; j++ )  // 适配器到插孔
		    if ( ! strcmp(adapt[i].out, recep[j]) )
				cap[i+m][j+m+k] = 1;
	}

	for ( i = 1; i <= n; i++ )  //插孔到t
		cap[i+m+k][t] = 1;
}

bool find_path () // BFS找增广路
{
	memset(pre,-1,sizeof(-1));
	memset(vis,0,sizeof(vis));
	queue<int> que;
	vis[s] = 1;
	que.push(s);

	while ( ! que.empty () )
	{
		int u = que.front ();
		que.pop ();
		for ( int v = t; v >= s; v-- )
		{
			if ( ! vis[v] && cap[u][v] > flow[u][v] )
			{
			    vis[v] = 1;
			    pre[v] = u;
			    if ( v == t ) return true;
			    que.push(v);
			}
		}
	}
	return false;
}

	
int max_flow()
{
	res = 0;
	memset(flow,0,sizeof(flow));
	while ( 1 )
	{
		if ( ! find_path() ) break;

		int tt = t;
		int minFlow = INF;
		while ( pre[tt] != -1 )
		{
			if ( minFlow > cap[pre[tt]][tt] - flow[pre[tt]][tt] )
				minFlow = cap[pre[tt]][tt] - flow[pre[tt]][tt];
			tt = pre[tt];
		}

		tt = t;
		while ( pre[tt] != -1 )
		{
			flow[pre[tt]][tt] += minFlow;
			flow[tt][pre[tt]] -= minFlow;
			tt = pre[tt];
		}
		res += minFlow;
	}
	return res;
}
		

int main()
{
	int i; 
	char name[25];

	scanf("%d",&n); 
	for ( i = 1; i <= n; i++ )
		scanf("%s",recep[i]);

	scanf("%d",&m); 
	for ( i = 1; i <= m; i++ )
		scanf("%s %s", name, device[i]);

	scanf("%d",&k);
	for ( i = 1; i <= k; i++ )
		scanf("%s %s",adapt[i].in, adapt[i].out);

	build_map();
	printf("%d\n", m - max_flow());

	return 0;
}


		

		


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值