题目链接:点击打开链接
题意:有A,B两台机器和k给任务,机器A有n中模式,机器B有m种模式,初始均在模式0,每个任务都可以由机器A的一种模式或者机器B的一种模式执行。每次切换模式都需要代价1,要求求最小的代价执行完所有的任务。
题解:最小点覆盖 = 最大匹配数。
感性理解过程:
假设二分图分为(X,Y;E)那么针对于任意点,都有如下两种情况
(1)点 i 同时连接着未匹配的点 和 匹配点
(2)点 i 连接匹配的点
若符合(1)那么我们会选择该点,因为我们若不选择该点,那么与该点连接的未匹配点将需要额外再去选择他。
若符合(2)那么我们选择该点或者选择该点连接的那个匹配点均可。
如图
设红线为一个最大匹配数,对与未匹配的y1而言覆盖他有两种方法,选择x1,或者选择自己本身。若选择y1我们想覆盖y2就需要在选择y2,那么总选择数就变成了4,若选择x1那么我们既覆盖了y1和y2.
所以对匹配边上的点而言,我们会发现我们的选择策略是判断该点是否连接着未匹配点。而正因为是匹配边上的点,所以你选择了其一那么必定会覆盖这条边上的两个点。那由这两条就可以看出来 最小点覆盖 == 最大匹配数。
代码如下
#include<bits/stdc++.h>
using namespace std;
const int N = 105;
int g[N][N];
int a[N],b[N],vis[N];
int n,m,k,ans;
int dfs(int i){
for(int j = 1 ; j < m ; j ++){
if(g[i][j] && !vis[j]){
vis[j] = 1;
if(b[j] == -1 || dfs(b[j])){
a[i] = j;
b[j] = i;
return 1;
}
}
}
return 0;
}
int main(){
int u,v,t;
while(scanf("%d",&n),n){
memset(g,0,sizeof(g));
scanf("%d%d",&m,&k);
for(int i = 0 ; i < k ; i ++){
scanf("%d%d%d",&t,&u,&v);
g[u][v] = 1;
}
ans = 0;
memset(a,-1,sizeof(a));
memset(b,-1,sizeof(b));
for(int i = 1 ; i < n ; i ++){
if(a[i] == -1){
memset(vis,0,sizeof(vis));
ans += dfs(i);
}
}
cout << ans << endl;
}
return 0;
}