1. 程式人生 > >最大二分圖匹配的C++程式碼實現

最大二分圖匹配的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!