POJ 1087 A Plug for UNIX(二分图匹配)

用set做字符串到标号的映射。

用floyd做一下可转移关系的传递,确定每两种端口间是否能转移。

然后根据这个关系建图,如果第i个空余端口可以转移成第j个需求端口,就从i到j建一条边。之后跑一个匈牙利算法即可。


注意floyd前,要把每个点到自己的转移可能初始化为1


坑:空间要开到400,因为理论上最多有400个不一样的端口出现。


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
#include <map>
int N,M,K;

map<string,int> Hs;
int Num=0,tot=0;
bool plug[405][405];
int dev[405];
int rec[405];
int sM[405];
int tM[405];
bool m[405][405];
bool vis[405];
bool dfs(int u){
	for(int i=0;i<M;i++){
		if(m[u][i]&&!vis[i]){
			vis[i]=1;
			if(tM[i]==-1||dfs(tM[i])){
				tM[i]=u;
				sM[u]=i;
				return 1;
			}
		}
	}
	return 0;
}

int solve(){
	int res=0;
	for(int i=0;i<N;i++){
		if(sM[i]==-1){
			memset(vis,0,sizeof(vis));
			if(dfs(i)) res++;
		}
	}
	return res;
}



int main(){
	scanf("%d",&N);
	for(int i=0;i<N;i++){
		string t;
		cin>>t;
		if(!Hs.count(t)) Hs[t]=Num++;
		rec[i]=Hs[t];
	}
	scanf("%d",&M);
	for(int i=0;i<M;i++){
		string t,k;
		cin>>k>>t;
		if(!Hs.count(t)) Hs[t]=Num++;
		dev[i]=Hs[t];
	}
	scanf("%d",&K);
	for(int i=0;i<K;i++){
		string s,t;
		cin>>t>>s;
		if(!Hs.count(s)) Hs[s]=Num++;
		if(!Hs.count(t)) Hs[t]=Num++;
		plug[Hs[s]][Hs[t]]=1;
	}
	for(int i=0;i<Num;i++){
		plug[i][i]=1;
	}

	for(int k=0;k<Num;k++){
		for(int i=0;i<Num;i++){
			for(int j=0;j<Num;j++){
				if(plug[i][k]&&plug[k][j]) plug[i][j]=1;
			}
		}
	}
	for(int i=0;i<N;i++){
		for(int j=0;j<M;j++){
			if(plug[rec[i]][dev[j]]){
				m[i][j]=1;
			}
		}
	}
	memset(sM,-1,sizeof(sM));
	memset(tM,-1,sizeof(tM));
	int res=M-solve();
	printf("%d",res);
	return 0;
}

你可能感兴趣的:(二分图最大匹配,匈牙利算法)