最小割。求最小数量的端点为不同颜色(黑白)的边,可以将黑点视为一个集合,白点视为一个集合,求两个集合相连的最小可能边数,其实就是最小割,但由于白黑点可能有很多个,需要一个源点指向所有黑点,所有白点指向汇点,这些边的容量均为INF,然后在图中求最大流,即最小割
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
int m,n,map[202][202];
int find_max_flow(){
bool findpath = true;
int ans = 0;
while(findpath){
bool visit[202] = {false};
int pre[202] = {-1},cur_flow,pre_flow,cur_point;
queue<int> q;
q.push(0);
visit[0] = true;
findpath = false;
while(!q.empty()){
int now = q.front(),i;
q.pop();
if(map[now][n+1] > 0){
findpath = true;
cur_point = now;
cur_flow = map[cur_point][n+1];
while(pre[cur_point] != 0){
pre_flow = map[pre[cur_point]][cur_point];
cur_flow = cur_flow > pre_flow ? pre_flow : cur_flow;
cur_point = pre[cur_point];
}
ans += cur_flow;
map[now][n+1] -= cur_flow;
map[n+1][now] += cur_flow;
while(pre[now] != 0){
map[pre[now]][now] -= cur_flow;
map[now][pre[now]] += cur_flow;
now = pre[now];
}
break;
}
for(i = 1;i <= n;i++)
if(map[now][i] > 0 && visit[i] == false){
q.push(i);
pre[i] = now;
visit[i] = true;
}
}
}
return ans;
}
int main(){
int INF = 400;
while(cin>>n>>m){
int i,a,b,h;
memset(map,0, sizeof(map));
for(i = 0;i < m;i++){
cin>>a>>b;
map[a][b] = 1;
map[b][a] = 1;
}
cin>>h;
for(i = 0;i < h;i++){
cin>>a;
map[0][a] = INF;
map[a][0] = INF;
}
cin>>b;
for(i = 0;i < b;i++){
cin>>a;
map[a][n+1] = INF;
map[n+1][a] = INF;
}
cout<<find_max_flow()<<endl;
}
return 0;
}