用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;
}