问题描述:
一、标题:
数字化婚姻配对尝试
二、题目:
建立一个模型,来模拟推导社会男女择偶过程。
为了模型简化,一个人的特性指标有三个,这里假设为财富、样貌、品格,每个指标均可取值1-100之间任意数字。同样也对这3项指标有自己的需求。这3个需求值取值范围都在1-98间,当然三者的和必须为100.所以任意一个人可以用以下数组来表述:
G(A、B、C、A1、B1、C1)G代表男,M代表女。
举例G11(80、50、40、10、30、60),表示男11号,拥有财富80、样貌50、品格40,对异性品格的偏好为:财富在乎程度百分之10、样貌在乎程度百分之30、品格在乎程度百分之60。
同样为了模型简化,假设信息是完全对称的,即是说,每个人都能一眼就能看清楚任意一个人的财富、样貌、品格。
还是为了模型简化,我建模所用样本为男女各100个,即男女人数相同。
每个人对异性的满意度将如下定义:每个偏好指标与异性的对应的禀赋指标相乘,三个指标的乘积再相加,即他(她)对某个异性的满意度。
举例G11(80、50、40、10、30、60)对M(50、60、80、40、10、50)的满意度为:
(10*50+30*60+60*80)= 7100分
相对的 MM 对 GG的满意度则为:
(40*80+10*50+50*40) = 5700分
好了,配对活动开始,设计的配对法则如下:
1、100个男方,顺序,轮流从0号到99号女方中挑选自己最满意的一位,然后向她发出配对邀请。
2、接受邀请最多的女方开始行动,对这些邀请的男性中,选择最满意的一位。
3、那么这两位配对成功,剔除出样本,剩下的99对继续这样配对。
4、循环该配对法则,直到最后一对男女配对成功。
在匹配时,如果发现有多个满意度相同的对象,要求自身三个属性(财富,外貌,品格)总和大的优先,如果再相同则id小的优先。如果有2位女士的选票相同,优先级规则同上。请把主角的id置为最小值,以便在前2个条件相同情况下,主角可以优先选择。
附件中,male.txt,female.txt,players.txt 分别是男士样本、女士样本和主角样本各 100位。 男女样本中,每行都代表一位男士或女士的基本属性,从左到右依次是ID, 样貌,品格,财富 , 期望样貌,期望品格,期望财富,没有加入性别,需要在解析时手动添加,每个txt文本的性别都是一样的,请注意。另外,主角样本中没有ID属性,换成了性别属性,其中 0表示女性,1表示男性,其余属性依次为样貌,品格,财富,期望样貌 ,期望品格,期望财富。建议把主角的id都设置为 -1,以便满足优先选择的条件。
设计思路:
1、设计一个个体基类(Person),其包含属性(ID, 样貌,品格,财富 , 期望样貌,期望品格,期望财富);
2、基类基础上派生出男士类(Male)、女士类(Female)和主角类(Players),主角类中需要增加属性性别(msex)并设计一个配对类(Pairing),该类中封装了此问题的核心配对操作;
3、从文件中依次读取数据,放入相应的vector容器中;
4、所有的男生向女生发出配对邀请;
5、找出收到邀请最多的男生,进行反配对选择;
6、输出配对结果。
代码实现:
#include<iostream>
#include<vector>
#include<iterator>
using namespace std;
//个体类
class Person
{
public:
//构造函数
Person(int id,int w,int f,int p,int pw,int pf,int pp):
mid(id)
,mwealth(w)
,mface(f)
,mpersonality(p)
,mper_wealth(pw)
,mper_face(pf)
,mper_personality(pp)
{}
int getid(){return mid;}
int getwealth(){return mwealth;}
int getface(){return mface;}
int getpersonality(){return mpersonality;}
int getper_wealth(){return mper_wealth;}
int getper_face(){return mper_face;}
int getper_personality(){return mper_personality;}
private:
int mid; //id
int mwealth; //财富
int mface; //样貌
int mpersonality; //品格
int mper_wealth; //需求财富
int mper_face; //需求样貌
int mper_personality;//需求品格
friend class Male;
friend class Female;
};
//男生类
class Male:public Person //派生类
{
public:
Male(int id,int w,int f,int p,int pw,int pf,int pp)
:Person(id,w,f,p,pw,pf,pp){}
//修改id
void setid(int id)
{
Person::mid = id;
}
private:
friend class Pairing; //声明友元类
};
//女生类
class Female:public Person //派生类
{
public:
//构造函数
Female(int id,int w,int f,int p,int pw,int pf,int pp)
:Person(id,w,f,p,pw,pf,pp){}
//修改id
void setId(int id)
{
Person::mid = id;
}
private:
vector<int> loveMaleId; //存储男生id,该男生对自己发送邀请
friend class Pairing;
};
//主角类
class Players:public Person
{
public:
Players(int id,int w,int f,int p,int pw,int pf,int pp,int sex)
:Person(id,w,f,p,pw,pf,pp),msex(sex){}
int getSex(){return msex;}
//类型转换函数 Players === > Female
Female makeFemale(Players &players)
{
Female female(players.getid(),players.getwealth(),players.getface(),players.getpersonality()
,players.getper_wealth(),players.getper_face(),players.getper_personality());
return female;
}
//类型转换函数 Players === > Male
Male makeMale(Players &players)
{
Male male(players.getid(),players.getwealth(),players.getface(),players.getpersonality()
,players.getper_wealth(),players.getper_face(),players.getper_personality());
return male;
}
private:
int msex; //表示性别
};
const int MAXPLAYERS = 100; //限定最大配对次数
class Pairing //配对类
{
public:
//初始化mmale
void filetommale()
{
char *path = "E:\male.txt";
int id,w,f,p,pw,pf,pp;
FILE *fp = fopen(path,"r");
if(NULL == fp)
{
printf("Do not open the file
");
exit(EXIT_FAILURE);
}
for(int i = 0;i < 100;i++)
{
fscanf(fp,"%d,%d,%d,%d,%d,%d,%d",&id,&w,&f,&p,&pw,&pf,&pp);
Male male(id,w,f,p,pw,pf,pp);
mmale.push_back(male);
}
fclose(fp);
}
//初始化female
void filetomfemale()
{
char *path = "E:\female.txt";
int id,w,f,p,pw,pf,pp;
FILE *fp = fopen(path,"r");
if(NULL == fp)
{
printf("Do not open the file
");
exit(EXIT_FAILURE);
}
for(int i = 0;i < 100;i++)
{
fscanf(fp,"%d,%d,%d,%d,%d,%d,%d",&id,&w,&f,&p,&pw,&pf,&pp);
Female female(id,w,f,p,pw,pf,pp);
mfemale.push_back(female);
}
fclose(fp);
}
//初始化players
void filetomplayers()
{
char *path = "E:\players.txt";
int id,w,f,p,pw,pf,pp,sex;
FILE *fp = fopen(path,"r");
if(NULL == fp)
{
printf("Do not open the file
");
exit(EXIT_FAILURE);
}
for(int i = 0;i < 100;i++)
{
fscanf(fp,"%d,%d,%d,%d,%d,%d,%d",&sex,&w,&f,&p,&pw,&pf,&pp);
Players players(-1,w,f,p,pw,pf,pp,sex);
mplayers.push_back(players);
}
fclose(fp);
}
//所有男生对女生发送邀请
void maletofemale(vector<Male> male,vector<Female>& female)
{
//外层循环,遍历男生
int i = 0;
auto it_male = male.begin();
for(;it_male != male.end();++it_male,i++)
{
//剔除配对失败的男生
if(it_male->getid() == -2){continue;}
int satisfaction = 0;//计算出满意度,并找出最心仪的
int maxSatisfaction = 0; //假定最心仪的
int index = 0; //记录最心仪女生在容器中的位置
//内层循环,找出该男生最心仪的女生,并向其发出邀请
int j = 0;
vector<Female>::iterator it_female = female.begin();
for(;it_female != mfemale.end();++it_female,j++)
{
//剔除配对失败的女生
if(it_female->getid() == -2){continue;}
satisfaction = it_male->getper_wealth() * it_female->getwealth()
+ it_male->getper_face() * it_female->getface()
+ it_male->getper_personality() * it_female->getpersonality();
if(satisfaction > maxSatisfaction) //满意度比较
{
maxSatisfaction = satisfaction;
index = j;
}
else if(satisfaction == maxSatisfaction) //满意度一样的话
{
int curSatisfactionNum = it_female->getwealth()
+ it_female->getface() + it_female->getpersonality();
int oldSatisfactionNum = female[index].getwealth()
+ female[index].getface() + female[index].getpersonality();
if(curSatisfactionNum > oldSatisfactionNum) //比较自身值
{
index = j;
}
else if(curSatisfactionNum == oldSatisfactionNum) //自身值一样
{
if(it_female->getid() < female[index].getid()) //比较id
{
index = j;
}
}
}
}
//将该男生id传入女生
female[index].loveMaleId.push_back(it_male->getid());
}
}
//找到邀请最多的女生
int inviteMax()
{
int maxPeople = 0; //表示收到最多邀请的个数
int femaleIndex = 0; //记录收到最多男生邀请的女生在容器中的位置
//遍历容器,找出那个女生收到男生的邀请最多
int i = 0;
vector<Female>::iterator it_female = mfemale.begin();
for(;it_female != mfemale.end();++it_female,i++)
{
if(it_female->loveMaleId.size() > maxPeople) //比较邀请人数
{
maxPeople = it_female->loveMaleId.size();
femaleIndex = i;
}
else if(it_female->loveMaleId.size() == maxPeople) //邀请人数一样
{
int curFemaleNum = it_female->getwealth() + it_female->getface() + it_female->getpersonality();
int oldFemaleNum = mfemale[femaleIndex].getwealth()
+ mfemale[femaleIndex].getface() + mfemale[femaleIndex].getpersonality();
if(curFemaleNum > oldFemaleNum) //比较自身值
{
femaleIndex = i;
}
else if(curFemaleNum == oldFemaleNum) //自身值一样
{
if(it_female->getid() < mfemale[femaleIndex].getid()) //比较id
{
femaleIndex = i;
}
}
}
}
return femaleIndex; //返回获取最多邀请的女生在容器中的位置
}
//女生挑选自己最心仪的一位男生,返回心意男生在容器中的位置
int femaleselectunique(vector<Female> &female)
{
//记录那个女生进行配对,注意idIndex表示配对女生在容器中的位置
int idIndex = inviteMax();
//此时已经知道那个女生收到的男生邀请是最多的
//接下来在这些男生中找到女生最心仪的一个男生
//遍历女生收到邀请的男生id,找出最心仪的一个
int satisfaction = 0; //表示满意程度
int maxSatisfaction = 0; //表示最满意的
int maleIndex = 0;
//外层循环向女生提出过邀请的男生
auto it1 = mfemale[idIndex].loveMaleId.begin();
for(;it1 != mfemale[idIndex].loveMaleId.end();++it1)
{
//内存循环找出对应男生id的全部信息
int j = 0;
vector<Male>::iterator it_male = mmale.begin();
for (;it_male != mmale.end();++it_male,++j)
{
if(it_male->getid() == *it1)
{
satisfaction = mfemale[idIndex].getper_wealth() * it_male->getwealth()
+ mfemale[idIndex].getper_face() * it_male->getface()
+ mfemale[idIndex].getper_personality() * it_male->getpersonality();
if(satisfaction > maxSatisfaction)
{
maxSatisfaction = satisfaction;
maleIndex = j;
}
else if(satisfaction == maxSatisfaction) //满意度比较
{
int curSatisfactionNum = it_male->getwealth() + it_male->getface() + it_male->getpersonality();
int oldSatisfactionNum = mmale[maleIndex].getwealth() + mmale[maleIndex].getface() + mmale[maleIndex].getpersonality();
if(curSatisfactionNum > oldSatisfactionNum) //自身比较
{
maleIndex = j;
}
else if(curSatisfactionNum == oldSatisfactionNum)
{
if(it_male->getid() < mmale[maleIndex].getid()) //id比较
{
maleIndex = j;
}
}
}
}
}
}
return maleIndex; //返回的是心仪男生最容器中的位置
}
//配对失败,将其余的男生重新分配到容器里-----仅仅是向配对失败女生发出过邀请的那一部分男生
void clearvector(vector<Female> &female,int mfemale)
{
vector<int> otherMaleId = female[mfemale].loveMaleId;
female[mfemale].loveMaleId.clear();
vector<Male> otherMale;
//外层循环其他男生
vector<int>::iterator it = otherMaleId.begin();
for(;it != otherMaleId.end();++it)
{
//内存循环找出对应男生的全部信息
vector<Male>::iterator it_male = mmale.begin();
int i = 0;
for(;it_male != mmale.end();++it_male,++i)
{
if(mmale[i].getid() == *it)
{
otherMale.push_back(mmale[i]); //将该男生对象插入
}
}
}
maletofemale(otherMale,female); //将剩余的男生重新分配
}
//输出配对情况
void show()
{
//获取主角数据
filetomplayers();
//定义一个计数器
int count = 0;
while(count < MAXPLAYERS)
{
filetommale(); //获取男生数据
filetomfemale(); //获取女生数据
//添加主角
if(mplayers[count].getSex(http://www.my516.com) == 0)
{
mfemale.push_back(mplayers[count].makeFemale(mplayers[count]));
}
else
{
mmale.push_back(mplayers[count].makeMale(mplayers[count]));
}
//此时已经将数据主角插入进去
//下面进行配对
//所有男生向女生发送邀请
maletofemale(mmale,mfemale);
int count_index = 0; //定义一个计数器
while(count_index < MAXPLAYERS)
{
//哪一个女生进行配对
int femaleId = inviteMax();
//女生选择自己最心仪的一个男生
int maleId = femaleselectunique(mfemale);
//检查是不是主角
if(mmale[maleId].getid() == -1 || mfemale[femaleId].getid() == -1)
{
cout<< "第" << count + 1 << "组player加入:" << mmale[maleId].getid() << ":" << mfemale[femaleId].getid() << endl;
break;
}
else
{
//修改男生id
mmale[maleId].setid(-2);
//修改女生id
mfemale[femaleId].setId(-2);
//去除选择该女生的男生
clearvector(mfemale,femaleId);
}
count_index++;
}
if(count_index == 100)
{
cout<< "第" << count + 1 << "组player加入:" << " " << ":" << " " << endl;
}
count++;
mmale.clear(); //清空
mfemale.clear(); //清空
}
}
private:
vector<Male> mmale;
vector<Female> mfemale;
vector<Players> mplayers;
};
int main()
{
Pairing a;
a.show();
return 0;
}
运行结果:
第1组player加入:-1:28
第2组player加入:33:-1
第3组player加入:4:-1
第4组player加入:11:-1
第5组player加入:46:-1
第6组player加入:65:-1
第7组player加入:-1:39
第8组player加入:-1:41
第9组player加入:49:-1
第10组player加入:-1:80
第11组player加入:-1:36
第12组player加入:-1:23
第13组player加入:-1:29
第14组player加入:-1:86
第15组player加入:36:-1
第16组player加入:-1:98
第17组player加入:-1:11
第18组player加入:-1:76
第19组player加入:20:-1
第20组player加入:-1:47
第21组player加入:-1:77
第22组player加入:41:-1
第23组player加入:-1:20
第24组player加入:57:-1
第25组player加入:-1:45
第26组player加入:-1:39
第27组player加入:-1:36
第28组player加入:-1:9
第29组player加入:-1:22
第30组player加入:79:-1
第31组player加入:-1:45
第32组player加入:-1:86
第33组player加入:22:-1
第34组player加入:-1:34
第35组player加入:45:-1
第36组player加入:97:-1
第37组player加入:67:-1
第38组player加入:-1:13
第39组player加入:-1:39
第40组player加入:-1:60
第41组player加入:-1:15
第42组player加入:56:-1
第43组player加入:-1:97
第44组player加入:26:-1
第45组player加入:71:-1
第46组player加入:-1:27
第47组player加入: :
第48组player加入:85:-1
第49组player加入:-1:97
第50组player加入:-1:46
第51组player加入:-1:49
第52组player加入:4:-1
第53组player加入:-1:35
第54组player加入:27:-1
第55组player加入:65:-1
第56组player加入:77:-1
第57组player加入:-1:73
第58组player加入:-1:94
第59组player加入:-1:83
第60组player加入:52:-1
第61组player加入:48:-1
第62组player加入:-1:53
第63组player加入:2:-1
第64组player加入:-1:12
第65组player加入:-1:78
第66组player加入:-1:84
第67组player加入:-1:69
第68组player加入:97:-1
第69组player加入:26:-1
第70组player加入:-1:97
第71组player加入:71:-1
第72组player加入:-1:78
第73组player加入:1:-1
第74组player加入:-1:28
第75组player加入:55:-1
第76组player加入:-1:28
第77组player加入:-1:10
第78组player加入:-1:81
第79组player加入:-1:87
第80组player加入:74:-1
第81组player加入:-1:63
第82组player加入:33:-1
第83组player加入: :
第84组player加入:79:-1
第85组player加入:66:-1
第86组player加入:9:-1
第87组player加入:66:-1
第88组player加入:-1:58
第89组player加入:37:-1
第90组player加入:14:-1
第91组player加入:-1:21
第92组player加入:54:-1
第93组player加入:-1:78
第94组player加入:77:-1
第95组player加入:78:-1
第96组player加入:-1:94
第97组player加入:53:-1
第98组player加入:-1:56
第99组player加入:-1:45
第100组player加入:14:-
---------------------