匈牙利算法模板 图的二分匹配 hdu 2063 过山车

http://acm.hdu.edu.cn/showproblem.php?pid=2063

过山车

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5243    Accepted Submission(s): 2320

Problem Description
RPG girls今天和大家一起去游乐场玩,终于可以坐上梦寐以求的过山车了。可是,过山车的每一排只有两个座位,而且还有条不成文的规矩,就是每个女生必须找个个男生做partner和她同坐。但是,每个女孩都有各自的想法,举个例子把,Rabbit只愿意和XHD或PQK做partner,Grass只愿意和linle或LL做partner,PrincessSnow愿意和水域浪子或伪酷儿做partner。考虑到经费问题,boss刘决定只让找到partner的人去坐过山车,其他的人,嘿嘿,就站在下面看着吧。聪明的Acmer,你可以帮忙算算最多有多少对组合可以坐上过山车吗?
 
Input
输入数据的第一行是三个整数K , M , N,分别表示可能的组合数目,女生的人数,男生的人数。0<K<=1000 1<=N 和M<=500.接下来的K行,每行有两个数,分别表示女生Ai愿意和男生Bj做partner。最后一个0结束输入。
 
Output
对于每组数据,输出一个整数,表示可以坐上过山车的最多组合数。
 
Sample Input
6 3 3 1 1 1 2 1 3 2 1 2 3 3 1 0
 
Sample Output
3
 
Author
PrincessSnow
 
Source
 
Recommend
lcy
 
模板题
ac代码:
 
#include <stdio.h>
#include <string.h>
#define max  510

int match[max][max];
int link[max];

bool  used[max];

int k,n,m;

bool dfs(int u)        //深搜遍历,寻找增广路径
{
    for(int v=1;v<=n;v++)
    {
        if(match[u][v]&&!used[v])
        {
            used[v]=true;
            if(link[v]==-1||dfs(link[v]))
            {
                link[v]=u;
                return true;
            }
        }
    }
     return false ;
}

int Xiong()
{
    int res=0;
    memset(link,-1,sizeof(link));
    for(int i=1;i<=m;i++)
    {
        memset(used,false,sizeof(used));
        if(dfs(i))                
            res++;                    //找到增广路径则匹配树加1
    }
    return res;
}

int main()
{
    
    int x,y;
    while(scanf("%d",&k)==1&&k)
    {
        memset(match,0,sizeof(match));     // 这里WA 了一次.. SB了 ....
         scanf("%d%d",&m,&n);
        for(int i=1;i<=k;i++)
        {
            scanf("%d%d",&x,&y);
            match[x][y]=1;
        }
        printf("%d\n",Xiong());
    }
    return 0;
}

 

 
 

匈牙利算法:(求偶图的最大匹配 注:偶图就是不存在奇数圈的连通图) 首先要明白几个概念:

二分图:设G=(V,E)是一个无向图,顶点集可以分割为两个互不相交的子集,并且图中每条边依附的顶点 都属于不同的子集,只有偶图有二分图,奇图没有;

匹配:在G的一个子图M中,M的边集都不依附于同余同一顶点,这样的图中边数最多的图称为图的最大匹配; 如果一个匹配中,包括图中所有的顶点,则称为此匹配为完全匹配,也叫完备匹配;

增广路的定义(也叫增广轨或者交错轨这个是匹配中一个最重要的概念) 如果P是图G中一条连通P是图G中一条连通两个未匹配顶点(起点和终点不在已匹配图中)的路径, 并且属M的边和不属M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径。

由增广路的定义可以推出下述三个结论:

1-P的路径长度必定为奇数,第一条边和最后一条边都不属于M,既起点和终点不在已匹配图中。  

2-P经过取反操作可以得到一个更大的匹配M’,(取反:原来在匹配中的边变成不在匹配中,不在的变成在每一次);   

3-M为G的最大匹配当且仅当不存在相对于M的增广路径,   用增广路求最大匹配(称作匈牙利算法,匈牙利数学家Edmonds于1965年提出)   

算法轮廓:   (1)置M为空  

 (2)找出一条增广路径P,通过取反操作获得更大的匹配M’代替M  

 (3)重复(2)操作直到找不出增广路径为止   

时间复杂度 邻接矩阵:最坏为O(n^3) 邻接表:O(nm)   

空间复杂度 O(n^2) O(m+n) 模板:

int dfs(int i)

{  

  int j;  

  for(j = 0;j<n; j++)   

{       

if(g[i][j]&&!mark[j])            //注意: g[i][j]放前面执行效率要高些因为g[i][j]为假比mark[j]=1次数多很多

       {

          mark[j] = 1;      

     if(link[j]==-1||dfs(link[j])) //link[j]==-1已找到了一条增广路,不等找其后继结点;

   {     

  link[j] = i;               //记录后继结点;

      return 1;

   }   

     }   

}   

return 0;                            //没找到返回0;

}

int main()

{    

int i,sum = 0;

    memset(link,-1,sizeof(link));      //初始化后继结点;   

  for(i = 0; i<n; i++)  

   {       

memset(mark,0,sizeof(mark));    //重新标记未访问;      

  if(dfs(i))                    

       sum++;                       //找到一条新的增广路加一;   

  }

}

匈牙利算法可以解决的图的问题:

(二分图) 1.图的最小点覆盖数 = 图的最大匹配数;

2.图的最大点独立集 = 图顶点数 - 图的最大匹配数;

3.图的最小路径覆盖数 = 原图的顶点数 - 原图拆点后形成的二部图的最大匹配数;

题目推荐:pku2446 pku2594 pku1325 pku1469

 
posted @ 2012-08-30 15:24  风之轻吟2012  阅读(543)  评论(0编辑  收藏  举报