UVA - 753 A Plug for UNIX 最大流

本文介绍了一个关于插口匹配的问题,并通过构建图论模型利用Dinic算法解决该问题。具体地,通过设置超级源点和汇点,以及使用转换器连接不同类型的插口来实现设备的有效匹配。

题目大意:有N个插
口,每个插口都有其相对应的类型,有M个电子设备,每个电子设备有其对应的插头,有K种转换器,转换器能将一种插口类型转换成另一种插口类型,转换器可以叠加使用,比如,转换器x b,和转换器b a,则两个转换器叠加的话,就变成了x a了,求要将这M个电子设备插入到相应的插口中,最少有几个没插入到相应插口中

解题思路:设置一个超级源点,连接着所有设备,权值为1,在设置一个超级汇点,连接这所有插口,权值为1,将设备的插头种类连接到响应的插口点,如果有转换器的话,将转换器相应的插口连接起来,连接起来权值为INF,这样图就建成了


#include<cstdio>
#include<cstring>
#define maxn 1010
#define INF 0x3f3f3f3f
using namespace std;
int N,M,K,e;
int d[maxn];
int head[maxn],next[maxn],f[maxn],v[maxn],q[maxn];
char str[maxn][30],phone[maxn][30],plug[maxn][30],temp[30];
void add(int x, int y, int flow) {

	v[e] = y;
	f[e] = flow;
	next[e] = head[x];
	head[x] = e;
	e++;

}
void init(){

	scanf("%d",&N);
	memset(head,-1,sizeof(head));
	e = 0;
	int s = 2;

	for(int i = 0; i < N; i++) {
		scanf("%s",str[s]);
		add(s,1,1);
		add(1,s,0);
		s++;	
	}

	scanf("%d",&M);

	for(int i = 1; i <= M; i++)
		scanf("%s%s",phone[i],plug[i]);

	scanf("%d",&K);
	int u,v;
	for(int i = 0; i < K; i++) {

		scanf("%s",temp);
		for( u = 2; u < s; u++) 
			if(strcmp(str[u],temp) == 0)
				break;
		if(u == s) {
			strcpy(str[s],temp);
			s++;	
		}

		scanf("%s",temp);
		for(v = 2; v < s; v++) 
			if(strcmp(str[v],temp) == 0)
				break;
		if(v == s) {
			strcpy(str[s],temp);
			s++;	
		}
		add(u,v,INF);
		add(v,u,0);
	}

	for(int i = 1; i <= M; i++) {
		for( v = 2; v < s; v++)
			if(strcmp(plug[i],str[v]) == 0)
				break;

		if(v != s) {
			add(s+i,v,1);
			add(v,s+i,0);
			add(0,s+i,1);
			add(s+i,0,0);
		}
	}
}

int bfs() {
	memset(d,-1,sizeof(d));
	d[0] = 0;
	int rear = 0;
	q[rear++] = 0;
	for(int i = 0; i < rear; i++)
		for(int j = head[q[i]]; j != -1; j = next[j])	
			if(d[v[j]] == -1 && f[j]) {
				d[v[j]] = d[q[i]] + 1;
				if(v[j] == 1)
					return 1;
				q[rear++] = v[j];
			}
	return 0;
}

int dfs(int cur,int a) {
	if(cur == 1)
		return a;
	int i;
	for(i = head[cur] ; i != -1; i = next[i]) {
		if(f[i] && d[cur] + 1 == d[v[i]])
			if(int t = dfs(v[i],f[i] < a ? f[i]:a)) {
				f[i] -= t;
				f[i^1] += t;
				return t;	
			}	
	}
	if(i == -1)
		d[cur] = -1;
	return 0;
}

int dinic() {
	int ans = 0,t;
	while(bfs()) {
		while(t = dfs(0,INF))
			ans += t;	
	}
	return ans;
}
int main() {

	int test;
	scanf("%d",&test);
	while(test--) {
		init();	
		printf("%d\n",M - dinic());
		if(test)
			printf("\n");
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值