点这里 |
---|
题意: 房间里有a
个插座和b
个电器设备,以及c
个适配器,相同接口的设备可以直接连接插座,不同接口的也可以使用适配器来连接。问最少有多少个设备没有插座可以用。
题解: 都这么问了,显然就是二分图最大匹配的问题了,可以选择用最大流的模板去做,也可以用比较简洁的匈牙利算法。问题在于适配器的问题怎么处理——Floyd传递闭包。下面代码为二分匹配的匈牙利算法。
过程中犯的错:
- cnt的初始化: 必须从1开始。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
using namespace std;
const int N = 400;
int T, a, b, c, cnt;
int atype[N], btype[N];
int vis[N], match[N], G[N][N];
string tem;
map<string, int> id;
int type(){ return id[tem] == 0 ? id[tem] = cnt++ : id[tem];}
void scan_init(){
cnt = 1; id.clear(); memset(G, 0, sizeof G);
scanf("%d", &a);
for(int i = 1; i <= a; i++){
cin >> tem;
atype[i] = type();
G[atype[i]][atype[i]] = 1;
}
scanf("%d", &b);
for(int i = 1; i <= b; i++){
cin >> tem; cin >> tem; btype[i] = type();
}
scanf("%d", &c);
for(int i = 1; i <= c; i++){
cin >> tem; int q = type();
cin >> tem; int p = type();
G[q][p] = 1;
}
}
void Floyd(){
for(int k = 1; k < cnt; k++)
for(int i = 1; i <=cnt; i++)
if(G[i][k])
for(int j = 1; j < cnt; j++)
if(G[k][j]) G[i][j] = 1;
}
bool dfs(int u){
for(int i = 1; i <= a; i++){
int v = atype[i];
if(!vis[v] && G[u][v]){
vis[v] = 1;
if(!match[v] || dfs(match[v])){
match[v] = u; return true;}
}
}
return false;
}
void solve(){
int sum = 0;
memset(match, 0, sizeof match);
for(int i = 1; i <= b; i++){
memset(vis, 0, sizeof vis);
if(dfs(btype[i])) sum ++;
}
printf("%d\n", b - sum);
}
int main(){
scanf("%d", &T);
while(T--){
scan_init();
Floyd();
solve();
if(T) printf("\n");
}
return 0;
}