关于二分图的匹配算法例子

最近挺忙的,突然发现之前写的一个关于匹配算法的案例。

一、问题描述

用数据结构的图解决伴侣匹配的问题,使得伴侣数量达到一个最多最优的一个匹配,也可以解决各种类似于伴侣匹配的问题,比如教师排课匹配,房地产匹配,等等类似的匹配问题。

首先考虑,男生和女生如何成为伴侣,如果两个人相互喜欢,则可以成为伴侣,当然,男生或者女生可能会同时喜欢多个异性对象,这就为这一伴侣匹配问题产生了一个可以调控的匹配,如图1,红线代表着他们相互喜欢,没有红线的当然是落单。

下面是数据结构的设计,让我们逐步解决这个问题。


1

二、数据结构设计

数据结构的设计,匹配的对象有两种不同的属性,第一个是男性,第二个是女性,我们可以根据这个特点去设计这个数据结构。

从正常情况下伴侣一般是异性,所以我们在设计这个数据结构的过程中避免掉同性匹配,这为我们后续的编程起到了减轻负担的作用。

接下来是设计:

 

男性:A  B  C  D  E  F  G  H

 

女性:1  2  3  4  5  6  7  8

 

这里是这样设计的:A 1 B 2 C 3 D 4 E 5 F 6 G 7 H 8

将他们混合,这样出现的邻接矩阵则是对称的,则他们为一张无序图。

这样设计的好处:避免了同性匹配

三、存储结构设计

存储结构的设计这里我采用的是邻接矩阵的存储方式。

设计目的:节省空间,只存储顶点的索引,使其更快速的遍历整个图。

如图2 3

                  
图2

                                                       算法设计                                                                 算法例图


以男性为主导说明,男性的索引为单数

说明:索引+2目的是让索引为单数,整个过程有三个标记,lovedneed, abandon;分别为是否被选,是否需要,是否放弃。

当某个异性顶点被选了之后,该异性的属性loved为真,反之为假。

当某个异性顶点需要被腾出来时,该异性的属性need为真,反之为假。

当某个男性无法匹配到任何异性时,该男性的属性abandon为真,反之为假。

直到选到最优的匹配数量时,输出结果。

结果:

男为主动:

    女为主动:


五、程序设计

   文件夹名称:grahp_mode

主程序:grahp_mode.cpp

头文件:Map0.h(图以及匹配算法) Node.h(顶点头文件)

CPP文件:Map0.cpp(核心算法) Node.cpp(顶点文件)

Map0.h

#pragma once
#include <vector>
using namespace std;
#include "Node.h"


class CMap0
{
public:
	CMap0(int capacity);
	~CMap0(void);
	 int times;
	  int num[100];
	  int num0[100];
	 string strtemp; // String类型暂时不用
	 string strman;
	 string strwomen;
     bool addNode(Node *pNode);  // 添加节点
	 void resetNode();   // 重置节点
	 bool setValueToMatrixForDirectedGraph(int row, int col, int val = 1); // √有向图设置邻接矩阵
	 bool setValuetoMatrixForUndirectedGraph(int row, int col, int val = 1); // 无向图设置邻接矩阵
	 bool setValuetoCoupleMatrixForUdirecteGraph(int row,int col,int val= 1);
	 void printMatri(); // 输出邻接矩阵
	 int jugleNum(int nodeIndex,int option=1);
	 
	 void depthCoupleTraverse0(int nodeIndex);

	 void depthCoupleTraverse1(int nodeIndex);
	  int findMax(int a[]);
	 void checkWomenOrman(int nodeIndex,int &num); // 检测还有没有漏掉的女士或者先生
	 void depthFirstTraverse(int nodeIndex);  // √深度优先遍历 
	 void breadthFristTraverse(int nodeIndex); // 广度优先遍历

	 void findCoupleBaseGraphMatching(int nodeIndex,int option);  // 匹配伴侣

	 void desighCapacity(int nodeIndex);  // 标记
	 void resetforCouple();  // 重置伴侣
	 
private:
	bool getValueFromMatrix(int row,int col,int &val);  // 获取图中的权位
	void breadthFristTraverseImpl(vector<int> preVec);// 实现广度优先遍历法(使用vector是方便迭代遍历)
	 

private:
	int m_iCapacity; // 图中最多可容纳的顶点数
	int m_iNodeCount; // 已经添加的顶点总个数
	Node *m_pNodeArray; //用来存放顶点数组
	int *m_pMatrix; // 邻接矩阵
};



Map0.cpp
#include "StdAfx.h"
#include "Map0.h"
#include <iostream>
#include <math.h>
#include <vector>

using namespace std;


CMap0::CMap0(int capacity) //初始化参数
{
	times = 0;
	strtemp = " "; 
	strman = "";
	strwomen = "";
	m_iCapacity = capacity;
	m_iNodeCount = 0;
	m_pNodeArray = new Node[m_iCapacity]; // 顶点数组分配内存
	m_pMatrix = new int[m_iCapacity * m_iCapacity]; // 邻接矩阵分配内存
	memset(m_pMatrix,0,m_iCapacity*m_iCapacity*sizeof(int));// 将邻接矩阵初始化(属于快捷方法,也可以利用for循环做初始化)

}


CMap0::~CMap0(void)
{
	delete []m_pNodeArray;
	delete []m_pMatrix;
}

bool CMap0::addNode(Node *pNode)
{
	if(pNode==NULL)
		return false;
	m_pNodeArray[m_iNodeCount].m_cData = pNode->m_cData; // 添加的数据索引由本生的顶点总数决定
	m_iNodeCount++;
	return true;
}

void CMap0::resetNode()
{
	for(int i=0; i<m_iCapacity ; i++)
	{
		m_pNodeArray[i].m_bIsVisited = false;
		m_pNodeArray[i].need = false;
		m_pNodeArray[i].loved=false;
		m_pNodeArray[i].isLine = false;
		m_pNodeArray[i].abandon = false;
	}
	m_iNodeCount = 0;
	times = 0;
}

void CMap0::resetforCouple()
{
	for(int i=0; i<m_iCapacity ; i++)
	{
		m_pNodeArray[i].loved=false;
		m_pNodeArray[i].m_bIsVisited = false;
		m_pNodeArray[i].isLine=false;
		m_pNodeArray[i].LineName = m_pNodeArray[i].m_cData;
	}
     
}

bool CMap0:: setValueToMatrixForDirectedGraph(int row, int col, int val) // 邻接矩阵有向图设值
{     // PS: 如果要使用这个函数的话,请使用两个For循环
	if(row < 0 && row > m_iCapacity)
	{
	  return false;
	}
	if(col < 0 && col > m_iCapacity)
	{
	  return false;
	}
	m_pMatrix[row * m_iCapacity + col] = val;
	return true;
}

                                               // 第一:row行,col 列,邻接矩阵的值
bool CMap0::setValuetoMatrixForUndirectedGraph(int row,int col, int val) // √邻接矩阵无向图设值
{
	if(row<0&&row>m_iCapacity){
	  return false;
	}
	if(col<0&&col>m_iCapacity){
	  return false;
	}
	m_pMatrix[row*m_iCapacity+col] = val; // val=1
	m_pMatrix[col*m_iCapacity+row] = val;
	return true;
}

bool CMap0::getValueFromMatrix(int row,int col,int &val)
{
	if(row < 0 && row > m_iCapacity)
	{
	  return false;
	}
	if(col < 0 && col > m_iCapacity)
	{
	  return false;
	}
	val =  m_pMatrix[row * m_iCapacity + col];

	return true;
}

void CMap0::printMatri()   // 输出邻接矩阵
{
	for(int i=0;i<m_iCapacity;i++)
	{ 
	for(int j=0;j<m_iCapacity;j++)
	{
		cout << m_pMatrix[i * m_iCapacity + j] << " "; 
	}
	cout << endl;
	}
}

void CMap0::depthCoupleTraverse0(int nodeIndex)  // 确认顶点是否有链接版本0
{
	int value = 0;
	m_pNodeArray[nodeIndex].m_bIsVisited = true; // 如果访问过则标上记号
	for(int i=0;i<m_iCapacity;i=i+2)   // 再从更深层迭代遍历
	{
	   getValueFromMatrix(nodeIndex,i,value);
	   if(value == 1)
	   {
		   m_pNodeArray[i].isLine=true;
		   m_pNodeArray[i].LineName = m_pNodeArray[nodeIndex].m_cData;
		   if(m_pNodeArray[i].m_bIsVisited)
		   {
		       continue;
		   }else
		   {
		       depthCoupleTraverse0(i);
		   }
	   }
	   else
	   {
	        continue;
	   }
	}
}
void CMap0::depthCoupleTraverse1(int nodeIndex)  // 确认顶点是否有链接版本1
{
	int value = 0;
	m_pNodeArray[nodeIndex].m_bIsVisited = true; // 如果访问过则标上记号
	for(int i=1;i<m_iCapacity;i=i+2)   // 再从更深层迭代遍历
	{
	   getValueFromMatrix(nodeIndex,i,value);
	   if(value == 1)
	   {
		   m_pNodeArray[i].isLine=true;
		   m_pNodeArray[i].LineName = m_pNodeArray[nodeIndex].m_cData;
		   if(m_pNodeArray[i].m_bIsVisited)
		   {
		       continue;
		   }else
		   {
		       depthCoupleTraverse1(i);
		   }
	   }
	   else
	   {
	        continue;
	   }
	}
}
void CMap0::depthFirstTraverse(int nodeIndex)
{
	int value = 0;
	// 先访问根节点
	cout << m_pNodeArray[nodeIndex].m_cData << " " ;
	m_pNodeArray[nodeIndex].m_bIsVisited = true; // 如果访问过则标上记号
	for(int i=0;i<m_iCapacity;i++)   // 再从更深层迭代遍历
	{
	   getValueFromMatrix(nodeIndex,i,value);
	   if(value == 1)
	   {
		   m_pNodeArray[i].isLine=true;
		   if(m_pNodeArray[i].m_bIsVisited)
		   {
		       continue;
		   }else
		   {
		       depthFirstTraverse(i);  // 迭代
		   }
	   }
	   else
	   {
	        continue;
	   }
	}
}

void CMap0::breadthFristTraverse(int nodeIndex) 
{
	//先访问根节点
	cout<<m_pNodeArray[nodeIndex].m_cData <<" ";
	m_pNodeArray[nodeIndex].m_bIsVisited = true;
	
	vector<int> curVec;
	curVec.push_back(nodeIndex);

	breadthFristTraverseImpl(curVec);
}



void CMap0::breadthFristTraverseImpl(vector<int> preVec)
{
	int value = 0;
	vector<int> curVec;
	for(int i = 0;i<(int)preVec.size();i++)
	{
	  for(int j = 0;j<m_iCapacity;j++)
	  {
	     getValueFromMatrix(preVec[i],j,value);
		 if(value == 1)
		 {
			 if(m_pNodeArray[j].m_bIsVisited)
			 {
			     continue;
			 }else
			 {
				 cout << m_pNodeArray[j].m_cData << " ";
				 m_pNodeArray[j].m_bIsVisited = true;
				 curVec.push_back(j);
			 }
		 }
	  
	  }
	}
	if(curVec.size()==0)
	{
	  return;
	}else
	{
	  breadthFristTraverseImpl(curVec);
	}
}

void CMap0::desighCapacity(int nodeIndex) // 标记的函数
{
	int value = 0;
	m_pNodeArray[nodeIndex].need = true;  
	for (int j =0 ;j<m_iCapacity;j++)
	{
		 getValueFromMatrix(nodeIndex,j,value);  
		if(value==1&&!m_pNodeArray[j].need)
		{
			m_pNodeArray[j].need = true;
		}
	}
}

void CMap0::checkWomenOrman(int nodeIndex,int &num)  // 检测还有没有漏掉的女士或者先生
{
	if(jugleNum(nodeIndex)){
	 depthCoupleTraverse0(nodeIndex);
	}else{
	 depthCoupleTraverse1(nodeIndex);
	}
		  for(int k =0;k<=m_iCapacity;k++){
			 if(m_pNodeArray[nodeIndex].m_cData==m_pNodeArray[k].LineName){
				  if(!m_pNodeArray[k].loved && !m_pNodeArray[k].need)
				   num=num+1;
			 }
	  }
		 resetforCouple();
		  
}
int CMap0::jugleNum(int nodeIndex,int option)  // 判断奇数偶数
{
	if(option==1){
   if(nodeIndex % 2 ==0){
	       return 0;
	  }
return 1;
	}else if(option==2){
	if(nodeIndex % 2 !=0){
	       return 0;
	  }
return 1;
	}else{
      return 0;	
	}
}

void CMap0::findCoupleBaseGraphMatching(int nodeIndex,int option) // 匹配对象
{	
	int value = 0;  // 
	int visited = 0; // 是否还剩下没被选的人(基数为确定女方,偶数为确定男方)
	 if(m_pNodeArray[nodeIndex].abandon){  // 如果被抛弃了就索引+2
	      nodeIndex=nodeIndex+2;
	 }
      for(int j = 0; j<m_iCapacity;j++)
	  {   
		   getValueFromMatrix(nodeIndex,j,value);
		   if(value==1)  
		{
			if(m_pNodeArray[j].loved)
			{
			   continue;
			}
			else if(m_pNodeArray[j].need==m_pNodeArray[nodeIndex].need)
			{   
			//	cout<<m_pNodeArray[nodeIndex].m_cData<<"-----";
				if(!jugleNum(nodeIndex)){
			    strman = strman + m_pNodeArray[nodeIndex].m_cData+m_pNodeArray[j].m_cData+" ";
				}else{
				strwomen = strwomen+ m_pNodeArray[nodeIndex].m_cData+m_pNodeArray[j].m_cData+" ";
				}
			//	cout<<m_pNodeArray[j].m_cData<<endl;
				m_pNodeArray[j].loved = true;
				m_pNodeArray[nodeIndex].loved = true;
				if(nodeIndex+2<=m_iCapacity)
				{
				  nodeIndex = nodeIndex+2;
				  findCoupleBaseGraphMatching(nodeIndex,option);
				  break;
				}
			}
		   }
	  }
	  visited=0;
	  checkWomenOrman(nodeIndex,visited); // 递归时先检测
	  if(visited==0&&value==1)
		  m_pNodeArray[nodeIndex].abandon=true;
	 if(visited!=0)
	  {  
		  ++times;
		  if(option==0){
		   num[times] = strman.length();
		   num0[times] = strwomen.length();
		  }else if(option ==1){
		  if(strman.length()==findMax(num)&&strman.length()!=0&×!=1){
			  cout<<strman;
		  cout<<"←←男主匹配:"<<strman.length()/3<<"对 ||女主匹配:"<<strwomen.length()/3<<"对 ←←←"<<"第 "<<times<<"次迭代"<<"←←←"<<endl<<endl;
		  }else if(strwomen.length()==findMax(num0)&&strwomen.length()!=0&×!=1){
		    cout<<strwomen;
		    cout<<"←←男主匹配:"<<strman.length()/3<<"对 ||女主匹配:"<<strwomen.length()/3<<"对 ←←←"<<"第 "<<times<<"次迭代"<<"←←←"<<endl<<endl;
		  }
		  }
		  strman = "";
		  strwomen = "";
	      desighCapacity(nodeIndex); // 标记需求
		  resetforCouple(); // 重置Couple
		  findCoupleBaseGraphMatching(jugleNum(nodeIndex),option);
	 }
}
int CMap0::findMax(int a[]){
	int max = 0;
	for(int i =0;i<20;i++){
		if(a[i]>max){
		  max = a[i];
		}
	}
	return max;

}

Node.h

#include <string>
#ifndef NODE_H
#define NODE_H
using namespace std;
class Node
{
public:
	Node(char data = 0);
	char m_cData;   // 顶点名
	bool m_bIsVisited; // 是否被看过
	bool loved;  // 是否被选了
    bool isLine; // 是否与其他点相连
	bool need; // 需要标号
	bool abandon; // 是否舍去
	char LineName;
	
};

#endif

Node.cpp

#include "StdAfx.h"
#include "Node.h"
#include <string>
using namespace std;


Node::Node(char data)
{
	m_cData = data;  // 节点数据
	m_bIsVisited = false; // 是否存在访问标识
	loved = false;
    isLine = false;
	need = false;
	abandon = false;
	LineName = data;
	

}

grahp_mode.cpp:

// greap_mode.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include "Map0.h"
#include <windows.h>




int main()
{
	CMap0 *cmap = new CMap0(24);
	int test = 0;

	Node *pNodeA = new Node('A');
	Node *pNode1 = new Node('1');
	Node *pNodeB = new Node('B');
	Node *pNode2 = new Node('2');
    Node *pNodeC = new Node('C');
    Node *pNode3 = new Node('3');
    Node *pNodeD = new Node('D');
    Node *pNode4 = new Node('4');
	Node *pNodeE = new Node('E');
	Node *pNode5 = new Node('5');
	Node *pNodeF = new Node('F');
	Node *pNode6 = new Node('6');
	Node *pNodeG = new Node('G');
	Node *pNode7 = new Node('7');
	Node *pNodeH = new Node('H');
	Node *pNode8 = new Node('8');
	Node *pNodeI = new Node('I');
	Node *pNode9 = new Node('9');
	Node *pNodeK = new Node('K');
	Node *pNode10 = new Node('0');
	Node *pNodeJ = new Node('J');
	Node *pNode11 = new Node('@');
	Node *pNodeL = new Node('L');
	Node *pNode12 = new Node('#');

	cmap->addNode(pNodeA);
	cmap->addNode(pNode1);
	cmap->addNode(pNodeB);
	cmap->addNode(pNode2);
	cmap->addNode(pNodeC);
    cmap->addNode(pNode3);
	cmap->addNode(pNodeD);
	cmap->addNode(pNode4);
	cmap->addNode(pNodeE);
	cmap->addNode(pNode5);
	cmap->addNode(pNodeF);
	cmap->addNode(pNode6);
	cmap->addNode(pNodeG);
	cmap->addNode(pNode7);
	cmap->addNode(pNodeH);
	cmap->addNode(pNode8);
	cmap->addNode(pNodeI);
	cmap->addNode(pNode9);
	cmap->addNode(pNodeK);
	cmap->addNode(pNode10);
	cmap->addNode(pNodeJ);
	cmap->addNode(pNode11);
	cmap->addNode(pNodeL);
	cmap->addNode(pNode12);



	cmap->setValuetoMatrixForUndirectedGraph(0,3);
	cmap->setValuetoMatrixForUndirectedGraph(0,5);
	cmap->setValuetoMatrixForUndirectedGraph(2,1);
	cmap->setValuetoMatrixForUndirectedGraph(2,3);
	cmap->setValuetoMatrixForUndirectedGraph(4,9);
	cmap->setValuetoMatrixForUndirectedGraph(6,7);
	cmap->setValuetoMatrixForUndirectedGraph(8,9);
	cmap->setValuetoMatrixForUndirectedGraph(10,9);
	cmap->setValuetoMatrixForUndirectedGraph(10,15);
	cmap->setValuetoMatrixForUndirectedGraph(12,11);
	cmap->setValuetoMatrixForUndirectedGraph(12,13);
	cmap->setValuetoMatrixForUndirectedGraph(12,19);
	cmap->setValuetoMatrixForUndirectedGraph(14,15);
	cmap->setValuetoMatrixForUndirectedGraph(14,17);
	cmap->setValuetoMatrixForUndirectedGraph(16,19);
	cmap->setValuetoMatrixForUndirectedGraph(18,21);
	cmap->setValuetoMatrixForUndirectedGraph(20,19);
	cmap->setValuetoMatrixForUndirectedGraph(22,21);
	cmap->setValuetoMatrixForUndirectedGraph(4,3);
	int control = 99;
	while(control!=5)
	{
	cout<<"-----------------------------------------婚介所-----------------------------------------"<<endl;
	cout<<"| 0.查看关系图 |"<<"| 1.深度优先遍历所有定点 |"<<"| 2.广度优先遍历所有定点 |"<<"| 3.男匹配女的结果 |"<<"| 4.女匹配男的结果 |"<<"| 5.重置 | "<<endl;
	cout<<"输入指令:";
		cin>>control;
		cout<<endl;
	if(control==0)
	{
	  cmap->printMatri();
	  cout<<endl;
	}else if(control == 1)
	{
		cout<<"深度优先遍历结果";
		cmap->depthFirstTraverse(0);
		cmap->depthFirstTraverse(6);
		cmap->depthFirstTraverse(12);
		cmap->depthFirstTraverse(21);
		cout<<endl;
		cmap->resetNode();
	}else if(control == 2)
	{
		cout<<"广度优先遍历结果";
		cmap->breadthFristTraverse(0);
		cmap->breadthFristTraverse(6);
		cmap->breadthFristTraverse(12);
		cmap->breadthFristTraverse(21);
		cout<<endl;
		cmap->resetNode();
	}else if(control == 3)
	{
	     cmap->findCoupleBaseGraphMatching(0,0);
		  cmap->resetNode();
		  Sleep(1000);
		  cmap->findCoupleBaseGraphMatching(0,1);
		 cout<<"以男性为主导选女性"<<endl;
		// cout<<cmap->strman;
		 cmap->resetNode();
	}else if(control == 4)
	{
	       cmap->findCoupleBaseGraphMatching(1,0);
		   cmap->resetNode();
		  Sleep(1000);
		  cmap->findCoupleBaseGraphMatching(1,1);
		   cout<<"以女性为主导选男性"<<endl;
		 //  cout<<cmap->strwomen;
		 cmap->resetNode();
	}else if(control == 5)
	{
	     cmap->resetNode();
	}
	}

	system("pause");
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值