最大二分图匹配的C++代码实现

    最大二分图匹配是典型的图论问题,一般有两种做法,一种是运用最大流的思想,不过这种方法效率太低,为O(VE^2),没有利用好二分图的特殊性质。另一种做法是匈牙利

算法,这种方法也是利用了增益路径的思想,但这种方法充分利用了二分图的性质,所以效率也是比较高的,为O(VE),而且还能进一步降低,不过我没有做那种优化,下面就是我

的代码:


#include<iostream>
#include<queue>
#include<vector>
#include<stdio.h>
using namespace std;

class B_Graph
{
private:
	struct vertex
	{
	  bool flag   ;             //是否被标记
	  int ver     ;            //标记的顶点
	  vector<int>adj;
	  vertex(bool f=0,int v=0):flag(f),ver(v){}

	};
	struct  Matching
	{
	   int ww;
	   int uu;
	  Matching(int w=0,int u=0):ww(w),uu(u){}
	  void print(){
	    cout<<"("<<ww<<","<<uu<<")  ";
	  }

	};
  int N1,N2;                    //点数,N1为V,N2为U
  vector<vertex>V;
  vector<Matching>M;
  public:
  B_Graph(int n1,int n2):N1(n1),N2(n2)
  {
     vertex tmp;
     Matching tmp1;
     for(int i=0;i<=N1+N2;i++)
       V.push_back(tmp);
      for(int i=0;i<=N1;i++)
       M.push_back(tmp1);
  }
  void merge(int i,int j)
  {
     V[i].adj.push_back(j);
  }
  void Max_B_Maching()
  {
     queue<int>Q;
     int i1=0;
     while(i1++<N1)
     Q.push(i1);
     while(!Q.empty())
     {
       int w=Q.front();Q.pop();
       if(w<=N1)                       //即w属于V
        {
            for(unsigned int i=0;i<V[w].adj.size();i++)
               {
                  int  u=V[w].adj[i];
                if(V[u].flag==0)
                     {
                        Matching tmp(w,u);
                        M[w]=tmp;
                        V[u].flag=1;
                        V[w].flag=1;
                        int v=w;
                        while(V[v].ver)
                        {
                           u=V[v].ver;
                           v=V[u].ver;
                           Matching tmp2(v,u);
                           M[v]=tmp2;
                           V[v].flag=1;
                        }
                        for(int i=1;i<=N1+N2;i++)
                          V[i].ver=0;
                         while(!Q.empty())
                         Q.pop();
                         for(int i=1;i<=N1;i++)
                         if(V[i].flag==0)
                         Q.push(i);
                         break;
                     }
                     else
                     {
                        if((M[w].ww!=w||M[w].uu!=u)&&V[u].ver==0)
                             {
                                V[u].ver=w;
                                Q.push(u);
                             }
                     }
                  }
            }
            else
            {
              int i=1;
               for(;i<=N1;i++)
                 if(M[i].uu==w)
                  {
                    V[i].ver=w;
                    break;
                  }
                  Q.push(i);
            }
     }
}
   void print_M_maching()
   {
      for(int i=1;i<=N1;i++)
      if(M[i].ww!=0)
       M[i].print();
   }
   int max_maching()
   {
      int Max=0;
     for(int i=1;i<=N1;i++)
      if(M[i].ww!=0)
        Max++;
        return Max;
   }
};
int main()
{
   freopen("in.txt","r",stdin);
   freopen("out.txt","w",stdout);
   int v,u,edge;
   while(cin>>v>>u>>edge)
   {
    B_Graph G(u,v);
    int a,b;
    while(edge--)
    {
      cin>>a>>b;
      G.merge(a,b);
    }
    G.Max_B_Maching();
    G.print_M_maching();
    cout<<endl<<"The Max_maching number is:"<<G.max_maching()<<endl;
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

下面是in.txt的测试数据:


5 5 10
1 6
1 7
2 6
3 6
3 8
4 8 
4 9
4 10
5 9
5 10
4 4 8
1 6
2 6 
2 7
3 6 
3 7
4 5
4 7
4 8


最后是out.txt的结果:

(1,7)  (2,6)  (3,8)  (4,9)  (5,10)  
The Max_maching number is:5
(1,6)  (2,7)  (4,5)  
The Max_maching number is:3


结果正确!OK!



  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值