题意:
n个插座和m个插头,k种转换器(每种都是无限个,可以把插头转换成其他类型的插头),求最少剩多少个插头没插上插座。
思路:
首先给所有插头或插座以及转换器中涉及到的类型编号。然后根据转换器建立类型之间的转化关系,接着用Floyd算法算出每个设备所有适配的类型,并将其容量设为INF,表示转换器数量充足,可以有多个设备用同一种转换器。
接着构建网络:所有的设备类型和源点连一条弧,容量为1(注意累加,比如有2个设备类型都是B,那么从源点到B的容量应该为2),所有的插座类型和汇点连弧,容量为1。
然后用最大流算法
#include <iostream>
#include <map>
#include <queue>
#include <vector>
#include <cstring>
#include <algorithm>
#define fi first
#define se second
#define pii pair<int,int>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 400+5;
int n;
int Cap[maxn][maxn], flow[maxn][maxn], dis[maxn];
map<string, int> mp;
int ID(string s){
int m = mp.size();
if(mp.count(s) == 0) mp.insert(make_pair(s,m));
return mp[s];
}
void Floyd(){
for(int k = 0; k < n; ++k){
for(int i = 0; i < n; ++i){
for(int j = 0; j < n; ++j){
Cap[i][j] = Cap[i][j]||(Cap[i][k]&&Cap[k][j]);
if(Cap[i][j]) Cap[i][j] = INF;
}
}
}
}
bool bfs(int s, int t){
memset(dis, -1, sizeof(dis));
queue<int> Q;
Q.push(s);
dis[s] = 0;
while(!Q.empty()){
int x = Q.front(); Q.pop();
for(int i = 0; i < n+2; ++i){
if(dis[i] == -1&&Cap[x][i] > flow[x][i]){
dis[i] = dis[x] + 1;
Q.push(i);
}
}
}
return dis[t] != -1;
}
int dfs(int s, int t, int f){
if(s == t||f == 0) return f;
int ans = 0;
for(int i = 0; i < n+2; ++i){
if(dis[i] == dis[s] + 1&&Cap[s][i] > flow[s][i]){
int a1 = min(f, Cap[s][i] - flow[s][i]);
int a2 = dfs(i, t, a1);
if(a2 == 0) continue;
flow[s][i] += a2;
flow[i][s] -= a2;
ans += a2;
f -= a2;
if(f <= 0) break;
}
}
return ans;
}
int dinic(int s, int t){
int ans = 0;
while(bfs(s, t)){
//printf("hh");
ans += dfs(s, t, INF);
}
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
int T,m,k; cin>>T;
while(T--){
memset(flow, 0, sizeof(flow));
memset(Cap, 0, sizeof(Cap));
mp.clear();
string s, s2;
vector<int> vec1, vec2;
cin>>n;
for(int i = 0; i < n; ++i) { cin>>s; vec1.push_back(ID(s));}
cin>>m;
for(int i = 0; i < m; ++i){ cin>>s>>s2; vec2.push_back(ID(s2));}
cin>>k;
for(int i = 0; i < k; ++i){
cin>>s>>s2;
Cap[ID(s)][ID(s2)] = INF;
}
n = mp.size();
for(int i = 0; i < n; ++i) Cap[i][i] = INF;
Floyd();
for(int i = 0; i < vec2.size(); ++i) Cap[n][vec2[i]] += 1; // 超级源点
for(int i = 0; i < vec1.size(); ++i) Cap[vec1[i]][n+1] = 1; // 超级汇点
int ans = dinic(n, n+1);
cout<<m-ans<<endl;
if(T) cout<<endl;
}
return 0;
}