二分图匹配----匈牙利算法之三
poj 1325 Machine Schedule
/*
转自http://hi.baidu.com/%8E%E1%D0%B3/blog/item/b26cbd0a03b134dc62d98609.html:
题意: 有两台机器A和B,分别有n种和m种不同的模式,有k个工作,每个工作都可以在那两个机器的某种特定的模式下处理,如job[0]既可以在A机器的3号模式下处理,也可以在B机器的4号模式下处理,
机器的工作模式改变只能通过重启来改变,通过改变工作的顺序和分配每个工作给合适的机器可以减少重启机器的次数,
题目要求的就是重启机器的最小次数,初始时两台机器都在0号模式下工作.
这里假设某工作在A机器上的工作模式为X[a],在B机器上的工作模式为Y[b],这样我们就可以以X和Y作为两个顶点集合建立二分图,
然后在X和Y中用最少的顶点数来覆盖所有的边,即转化为求二分图的最小点覆盖问题,根据König定理即是求解二分图的最大匹配数.
这题有点需要注意:机器A和机器B开始时即在模式0下工作,所以如果机器A或机器B中有机器在模式0下工作时,这时就不需要重启机器,
解决该问题的方法有两个:
1>在建立二分图时,只有在x与y都不为0时才将x与y之间标记为有边.
2>在进行搜索和匹配的过程中,从顶点1开始而不是从0开始进行.
*/
poj 1325 Machine Schedule
#include<iostream> //求二分图的最小覆盖点集,由König定理可知二分图的最小覆盖点集与二分图最大匹配等价
#include<cstring>
using namespace std;
int n,m,k;
int result[101]; //result记录V2中的点匹配的点的编号
int edge[101][101],vis[101]; //vis记录V2中的每个点是否被搜索过
bool find(int a)
{
for(int i=2;i<=m;++i)
{
if(edge[a][i]==1&&vis[i]==0) //如果节点i与a相邻并且未被查找过
{
vis[i]=1; //标记i为已查找过
if( result[i]==0 || find(result[i])==true ) //如果i未在前一个匹配M中或者 i在匹配M中,但是从与i相邻的节点出发可以有增广路
{
result[i]=a; //记录查找成功记录
return true; //返回查找成功
}
}
}
return false;
}
int main()
{
while(scanf("%d",&n),n)
{
scanf("%d%d",&m,&k);
memset(edge,0,sizeof(edge));
memset(result,0,sizeof(result));
int job,t1,t2;
while(k--)
{
scanf("%d%d%d",&job,&t1,&t2);
edge[t1+1][t2+1]=1;
}
int ans=0;
for(int i=2;i<=n;++i)
{
memset(vis,0,sizeof(vis)); //清空上次搜索时的标记
if(find(i)==true) //从节点i尝试扩展
ans++;
}
printf("%d\n",ans);
}
return 0;
}