UVA753 A Plug for UNIX 题解

题目描述:

n n n 个插座, m m m 个设备和 k ( n , m , k ≤ 100 ) ( n , m , k ≤ 100 ) k (n, m, k \leq 100)(n,m,k \leq 100) k(n,m,k100)(n,m,k100)种转换器,每种转换器有无限多。已知每个插座的类型,每个设备的插头类型,以及每种转换器的插座类型和插头类型。插头和插座类型都用不超过 2424 个字母表示,插座只能插到类型名称相同的插座中。 例如,有 44 个插座,类型分别为 A,B,C,D;有 5 个设备,插头类型分别为 B,C,B,B,X;还有三种转换器,分别是 B->X,X->A 和 X->D。这里用 B -> X 表示插座类型为 BB,插头类型为 XX,因此一个插座类型为 BB 的设备插上这种转换器之后就 “变成” 了一个插头类型为 X 的设备。转换器可以级联使用,例如插头类型为 AA 的设备依次接上 A->B, B->C, C->D 这 33 个转换器之后会 “变成” 插头类型为 DD 的设备。 要求插的设备尽量多。问最少剩几个不匹配的设备。

解题思路:

这题思路比较简单,主要考察二分图的最大匹配算法。我们只需先求出每个电器通过转换器能插哪几个插头,那么问题就变成有 n n n个插头, m m m个电器,并且告诉你每个电器能插哪几个插头,求最大同时能插几个电器。这就变成了裸的二分图最大匹配题目,我们可以使用相应的算法来完成,我这里使用了匈牙利算法。
需要注意的是:插头类型可能不止100个,最多可能有400个。还有就是输出格式,每组数据之间输出一个空行。

代码:

#include <bits/stdc++.h>
using namespace std;
int t,a[405][405],x[105],y[105];
int book[105],match[105];
map<string,int> mp;
int n,m,k;
int dfs(int p)
{
	for(int i=1;i<=n;i++)
	{
		int to=x[i];
		if(book[i]||!a[y[p]][to])
			continue;
		book[i]=1;
		if(!match[i]||dfs(match[i]))
		{
			match[i]=p;
			return 1;
		}
	}
	return 0;
}
int main(){
	
	cin>>t;
	while(t--)
	{
		mp.clear();
		memset(a,0,sizeof(a));//存图,a[i][j]表示插头是i的电器 能否 插j插头 
		memset(x,0,sizeof(x));//插头 
		memset(y,0,sizeof(y));//电器 
		//输入插头 
		cin>>n;
		int cnt=0;
		for(int i=1;i<=n;i++)
		{
			string s;
			cin>>s;
			if(!mp[s])
				mp[s]=++cnt; 
			x[i]=mp[s];
		}	
		//输入电器 
		cin>>m;
		for(int i=1;i<=m;i++)
		{
			string s1,s2;
			cin>>s1>>s2;
			if(!mp[s2])
				mp[s2]=++cnt;		
			y[i]=mp[s2];
			a[y[i]][y[i]]=1; 
		}
		//输入转换器 
		cin>>k;
		for(int i=0;i<k;i++)
		{
			string s1,s2;
			cin>>s1>>s2;
			if(!mp[s1])
				mp[s1]=++cnt;
			if(!mp[s2])
				mp[s2]=++cnt;
			a[mp[s1]][mp[s2]]=1;
		}
		//floyd算法 
		for(int k=1;k<=cnt;k++)
			for(int i=1;i<=cnt;i++)
				for(int j=1;j<=cnt;j++)
					a[i][j]=a[i][j]||(a[i][k]&&a[k][j]);
		//匈牙利算法 
		int ans=0;
		memset(match,0,sizeof(match));
		for(int i=1;i<=m;i++)
		{
			memset(book,0,sizeof(book));
			if(dfs(i))
				ans++;
		}
		cout<<m-ans<<endl;
		if(t)cout<<endl;
	} 
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值