题意:有n个插座,m个设备,k种适配器用于转接(每种无限多),接口有自己的类型,只有相同的类型才能接上。问最少有多少设备不能接上插座。
思路:最大流。建图开始有一点困难了,源->设备->(适配器)->插座->汇这样建。。程序复杂了不是那么好调,坑了好久。。其实只要建图建好了,剩下的不是问题。
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <cstdlib>
#include <string>
#include <memory.h>
#include <vector>
#include <queue>
#include <stack>
#include <ctype.h>
#define INF 1000000000
using namespace std;
int t,n,m,k;
string nn[110];
string mm[110];
string kk1[110];
string kk2[110];
int map[310][310];
int main(){
cin>>t;
while(t--){
memset(map,0,sizeof(map));
cin>>n;//插座
for(int i=1;i<=n;i++){
cin>>nn[i];
}
cin>>m;//设备
string dev;
for(int i=1;i<=m;i++){
cin>>dev>>mm[i];
}
cin>>k;//适配器
for(int i=1;i<=k;i++){
cin>>kk1[i]>>kk2[i];
}
//源到设备
for(int i=1;i<=m;i++){
map[0][n+i]=1;
}
//设备到插座
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(nn[i]==mm[j]){
map[n+j][i]=1;
}
}
}
//插座到汇
for(int i=1;i<=n;i++){
map[i][n+m+k+1]=1;
}
//设备到适配器
for(int i=1;i<=m;i++){
for(int j=1;j<=k;j++){
if(mm[i]==kk1[j]){
map[n+i][n+m+j]=1;
}
}
}
//适配器之间
for(int i=1;i<=k;i++){
for(int j=1;j<=k;j++){
if(kk1[i]==kk2[j]){
map[n+m+j][n+m+i]=INF;
}
}
}
//适配器到插座
for(int i=1;i<=n;i++){
for(int j=1;j<=k;j++){
if(nn[i]==kk2[j]){
map[n+m+j][i]=INF;
}
}
}
//最大流
int ans=0;
int pre[310];
int a[310];
int flow[310][310];
memset(flow,0,sizeof(flow));
while(true){
memset(a,0,sizeof(a));
queue<int> que;que.push(0);
while(!que.empty()){
int cur=que.front();que.pop();
for(int i=0;i<=(n+m+k+1);i++){
if( !a[i]&&(map[cur][i]>flow[cur][i]) ){
a[i]=1;
pre[i]=cur;
que.push(i);
if(i==(n+m+k+1))break;
}
}
}
if(!a[n+m+k+1])break;
ans++;
for(int i=(n+m+k+1);i!=0;i=pre[i]){
flow[pre[i]][i]++;
flow[i][pre[i]]--;
}
}
cout<<m-ans<<endl;
if(t)cout<<endl;
}
return 0;
}