No.8.4 二分图最大匹配 - 增广路

一、二分图

如果一个图的所有顶点可以被分为X和Y两个集合,所有边的顶点恰好一个属于X,另一个属于Y,且集合内的点互不相连,这样的图成为二分图。

算法思路:

  1.先从一个未匹配的点 u 开始,任选一条从 u 出发的边 u->v,若v未配对,return;

     若v已经配对,尝试update原来的配对关系;

  2.若u v配对失败,重新选择 u 出发的边,继续匹配,直到配对成功,或者尝试完所有u出发的边;

  3.继续其他点的匹配尝试;

 

int n,m,sum=0;

int e[9][9],book[9];

int match[100];

int dfs(int u){

  int i;

  for(i=n/2;i<=n;i++){  // 只需遍历Y集合

    if(book[i]==0 && e[u][i] ==1){  //对任一点 u ,先从它的相邻边中找匹配顶点

      book[i]=1;

      if(match[i]==0 || dfs(match[i])){ // C.如果 i 未配对,或者找到了新的配对,才能执行以下更新

        match[i]=u;

        match[u]=i;

        printf("%d->%d\t",u,i);

        return 1;

      }

    }

  }

  return 0;

}

int main(){

  int i,j,x,y;

  scanf("%d %d",&n,&m);

  for(i=1;i<=m;i++){

    scanf("%d %d",&x,&y);

    e[x][y] =1;

    e[y][x] =1;

  }

  for(i=1;i<=n;i++)   match[i]=0;

  for(i=1;i<=n/2;i++){  // A.只需遍历X集合

    for(j=n/2;j<=n;j++) book[j]=0;  // B.

    if( dfs(i) )   sum++;

  }

  printf("\n%d ",sum);

  getchar();getchar(); return 0;

}

No.8.4 二分图最大匹配 - 增广路

 

 

 

二、总结

1.想不到的点:

  a. X,Y仅仅是两个逻辑存在的集合,点都是在同一个无向图里面,所以可以for遍历,标记A处;但是不应该遍历图的所有点,只需遍历X集合,否则会出现意想不到的问题,比如:

  No.8.4 二分图最大匹配 - 增广路 这是遍历X集合的结果,即 for(i=1;i<=n/2;i++){  // A.;

   No.8.4 二分图最大匹配 - 增广路这是遍历图的所有节点产生的结果,即 for(i=1;i<=n;i++){  // A.;

  b. 对每个点 u 进行配对之前,要先把之前的标记已搜索点(Y集合)清空,标记B处

  c. 被匹配点 i ,只有它未配对,或者它的原来配对对象可以重新找到配对对象的情况下,才能与 u 进行配对,这会触发dfs递归匹配操作,如果递归中有一组匹配失败,整个匹配都失败!

 

No.8.4 二分图最大匹配 - 增广路

上一篇:dp动态规划 背包问题


下一篇:Collections的一些常用方法