POJ 3041 Asteroids (匈牙利算法)

来源:互联网 发布:js 设置button文字 编辑:程序博客网 时间:2024/05/16 07:35

题意:矩阵上有一些小行星,占据了一些格子,我们每次操作可以清理一列中的所有小行星,也可以清理一行中的所有小行星,问最少进行多少次操作可以清理掉所有的小行星。


分析:一个小行星,要么清理该行,要么该列。所以也就是每个小行星对应的行列中至少选择一样来清理。下面建图,如果我们把每行看成集合一中的点,每列看成集合二中的点,一个小行星看成是其对应行列的连线,那么也就是说不能存在某一条连线两边的点都没有被选中的情况。这恰好就是二分图最小点集覆盖的要求。 

#include <stdio.h>#define N 501int grid[N][N] ;        //矩阵的行列分别属于二分图的两个顶点集V1、V2,其中行x∈V1,列y∈V2,存储数据方式:可达矩阵 int flag[N] ;       int link[N] ;       //记录V2中y值所匹配的x(V1中)int dfs ( int const x , int const n )       //匈牙利算法{    int y ;    for ( y = 1 ; y <= n ; y ++ )    {       if ( grid[x][y] && 0 == flag[y] )       {           flag[y] = 1 ;           if ( 0 == link[y] || dfs ( link[y] , n ) )           {               link[y] = x ;               return 1 ;           }       }    }    return 0 ;}void Input ( int const k ){    int i ;    for ( i = 1 ; i <= k ; i ++ )    {        int x , y ;        scanf ("%d%d" , & x , & y ) ;        grid[x][y] = 1 ;    }}void Init_Flag ( ){    int i ;    for ( i = 0 ; i < N ; i ++ )    {        flag[i] = 0 ;    }}intmain ( ){    int n , k ;    scanf ("%d%d" , & n , & k ) ;    Input ( k ) ;    int count ;    count = 0 ;    int x ;    for ( x = 1 ; x <= n ; x ++ )    {        Init_Flag ( ) ;        if ( dfs ( x , n ) )        {            count ++ ;        }    }    printf ("%d\n" , count ) ;    return 0 ;}


记住条性质: 二分图最大匹配的König定理  最小点覆盖数 = 最大匹配数
最小点集覆盖==最大匹配。在这里解释一下原因,首先,最小点集覆盖一定>=最大匹配,因为假设最大匹配为n,那么我们就得到了n条互不相邻的边,光覆盖这些边就要用到n个点。现在我们来思考为什么最小点击覆盖一定<=最大匹配。任何一种n个点的最小点击覆盖,一定可以转化成一个n的最大匹配。因为最小点集覆盖中的每个点都能找到至少一条只有一个端点在点集中的边(如果找不到则说明该点所有的边的另外一个端点都被覆盖,所以该点则没必要被覆盖,和它在最小点集覆盖中相矛盾),只要每个端点都选择一个这样的边,就必然能转化为一个匹配数与点集覆盖的点数相等的匹配方案。所以最大匹配至少为最小点集覆盖数,即最小点击覆盖一定<=最大匹配。综上,二者相等。


设G=(V,E)是一个无向图。如顶点集V可分割为两个互不相交的子集V1,V2之并,并且图中每条边依附的两个顶点都分属于这两个不同的子集。则称图G为二分图。二分图也可记为G=(V1,V2,E)。
给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配
选择这样的子集中边数最大的子集称为图的最大匹配问题(maximal matching problem) 
如果一个匹配中,|V1|<=|V2|且匹配数|M|=|V1|则称此匹配为完全匹配,也称作完备匹配。特别的当|V1|=|V2|称为完美匹配。
M-交错路:p是G的一条通路,如果p中的边为属于M中的边与不属于M但属于G中的边交替出现,则称p是一条M-交错路。
M-饱和点:对于v∈V(G),如果v与M中的某条边关联,则称v是M-饱和点,否则称v是非M-饱和点。
M-可增广路:p是一条M-交错路,如果p的起点和终点都是非M-饱和点,则称p为M-可增广路。
 
由增广路的定义可以推出下述三个结论:
 
1-P的路径个数必定为奇数,第一条边和最后一条边都不属于M。
2-将M和P进行取反操作可以得到一个更大的匹配M’。
3-M为G的最大匹配当且仅当不存在M的增广路径。
算法轮廓:
⑴置M为空
⑵找出一条增广路径P,通过异或操作获得更大的匹配M’代替M
⑶重复⑵操作直到找不出增广路径为止