一、问题描述
用数据结构的图解决伴侣匹配的问题,使得伴侣数量达到一个最多最优的一个匹配,也可以解决各种类似于伴侣匹配的问题,比如教师排课匹配,房地产匹配,等等类似的匹配问题。
首先考虑,男生和女生如何成为伴侣,如果两个人相互喜欢,则可以成为伴侣,当然,男生或者女生可能会同时喜欢多个异性对象,这就为这一伴侣匹配问题产生了一个可以调控的匹配,如图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
![](https://i-blog.csdnimg.cn/blog_migrate/64a609e7e7baa7ee2bb84489887ef202.png)
算法设计 算法例图
![](https://i-blog.csdnimg.cn/blog_migrate/9eee7bd20cbb2079066d595d086a7f5c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a2424ed16a6a50c003595bc07895208e.png)
以男性为主导说明,男性的索引为单数
说明:索引+2目的是让索引为单数,整个过程有三个标记,loved,need, abandon;分别为是否被选,是否需要,是否放弃。
当某个异性顶点被选了之后,该异性的属性loved为真,反之为假。
当某个异性顶点需要被腾出来时,该异性的属性need为真,反之为假。
当某个男性无法匹配到任何异性时,该男性的属性abandon为真,反之为假。
直到选到最优的匹配数量时,输出结果。
结果:
男为主动:
![](https://i-blog.csdnimg.cn/blog_migrate/08ee7b087f105d0ad613c0a530ffb8df.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a0e57024f827e16afbd6244bd42d6ec9.png)
五、程序设计
文件夹名称:grahp_mode
主程序:grahp_mode.cpp
头文件:Map0.h(图以及匹配算法) Node.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; // 邻接矩阵
};
#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;
}
#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
#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;
}
// 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;
}