中兴捧月杯第一题初赛
一、标题:
数字化婚姻配对尝试
二、题目:
建立一个模型,来模拟推导社会男女择偶过程。
为了模型简化,一个人的特性指标有三个,这里假设为财富、样貌、品格,每个指标均可取值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、循环该配对法则,直到最后一对男女配对成功。
三、初赛阶段要求:
1、编程语言为java,C++或C语言任意一种;运行环境windows。
2、能让用户输入自己的参数以及对各项数值的偏好,然后随机生成100位男性100位女性(包括用户在内。如果用为男性则为99男100女),数值全部随机但需满足题设限制。按照上述规则给出一个匹配结果呈现给用户。
3、若采用c/c++,要输出可执行程序;若采用java,给出jar和bat。
4、在匹配时,如果发现有多个满意度相同的对象,要求自身三个属性(财富,外貌,品格)总和大的优先,如果再相同则id小的优先。如果有2位女士的选票相同,优先级规则同上。请把主角的id置为最小值,以便在前2个条件相同情况下,主角可以优先选择。
5、程序读取指定的配置文件,获取样本,然后根据指定的输入,输出结果。同时会给出一组源数据和标准答案给学生自测。最后再让学生根据不同的,指定的输入,给出考试答案。
请点击下载配置文件附件。附件中,male.txt,female.txt,players.txt 分别是男士样本、女士样本和主角样本各 100位。 男女样本中,每行都代表一位男士或女士的基本属性,从左到右依次是ID, 样貌,品格,财富 , 期望样貌,期望品格,期望财富,没有加入性别,需要在解析时手动添加,每个txt文本的性别都是一样的,请注意。另外,主角样本中没有ID属性,换成了性别属性,其中 0表示女性,1表示男性,其余属性依次为样貌,品格,财富,期望样貌 ,期望品格,期望财富。建议把主角的id都设置为 -1,以便满足优先选择的条件。
给出标准答案2组,用于考生自测:
1号主角(文本第一行),选择的对象属性为(6,18,82,87,3,10)
2号主角(文本第二行),选择的对象属性为(27,74,22,22,58,20)
同时要求考生输出9号主角(0,72,55,53,8,87,5),19号主角(0,11,4,63,22,60,18),47号主角(1,19,8,21,1,53,46),83号主角(1,23,11,17,58,31,11),99号主角(1,26,66,1,78,11,11)以及100号主角(0,68,28,19,43,11,46)的选择结果。
四、初赛阶段审核标准及评价细则
1. 功能分(40分)
如果学生最后答案错误,则该项得0分
如果答案正确,得40分
2. 代码质量分(30分)
可读性,整洁性,健壮性,可扩展性,封装性
3. 用户体验(10分)
界面美观,操作方便,有必要的信息提示
4. 代码文档质量(10分)
代码清晰,易读,注释完整
5. 单元测试(10分)
关键函数或容易出错部分应该有单元测试保证
#include <iostream> #include <fstream> #include <ostream> #include <vector> #include <algorithm> #include <ctime> #include <cstdlib> using namespace std; int M = 100; //表示匹配对数 //将人用类Person表示 struct Person{ int sex; int id; int fortune; int appearance; int character; int wFortune; int wAppearance; int wCharacter; int matchID; //匹配id号 int satisfyID; //当为男性是指最满意的对方id号,女性是指被邀请的数目 bool match; //是否成功,true表示已配对,false表示没有 Person(int s=0, int i=-2, int f=0, int a=0, int c=0, int wf=0, int wa=0, int wc=0, int mi=0, int si=0, bool m=false): sex(s),id(i),fortune(f),appearance(a),character(c), wFortune(wf),wAppearance(wa),wCharacter(wc),matchID(mi),satisfyID(si),match(m){} }; //为了在匹配时能唯一确定满意度顺序,定义了一个辅助类SatDegree用于重载">"运算符 struct SatDegree{ int satD; //对对方的满意度 int sum3; //对方三个属性的总和 int id; //对方的id号 SatDegree(int sd = 0, int s3 = 0, int i = -2):satD(sd), sum3(s3), id(i){} }; // 数据结构,男性、女性都按id+1依次存储,相当于hash表 vector<Person> male(M+1);//男性数组 vector<Person> female(M+1);//女性数组 //测试 vector<vector<int> > satm2fM(M+1,vector<int>(M+1,0)); vector<vector<int> > satf2mM(M+1,vector<int>(M+1,0)); vector<vector<int> > invitedM(M+1,vector<int>(2,0)); //重载">"号,当满意度相等时,其属性总和大的较大,但都相等时,id号小的大 bool operator >(const SatDegree& sd1, const SatDegree& sd2) { if (sd1.satD > sd2.satD) return true; else if (sd1.satD == sd2.satD) if (sd1.sum3 > sd2.sum3) return true; else if (sd1.sum3 == sd2.sum3) if (sd1.id <= sd2.id) //"=="号是考虑到自己同自己比较的情况 return true; else return false; else return false; else return false; } ostream& operator<<(ostream& os, const Person& p) { return os << p.fortune << \',\' << p.appearance << \',\' << p.character << \',\' << p.wFortune << \',\' << p.wAppearance << \',\' << p.wCharacter; } istream& operator>>(istream& is, Person& p) { char comma; return is >> p.id >> comma >> p.fortune >> comma >> p.appearance >> comma >> p.character >> comma >> p.wFortune >> comma >> p.wAppearance >> comma >> p.wCharacter; } int sum3(Person p) { return p.fortune+p.appearance+p.character; } SatDegree satisfy(Person p1,Person p2)//不同性别的p1对p2的满意度 { SatDegree SD; SD.satD = p1.wFortune*p2.fortune+p1.wAppearance*p2.appearance+p1.wCharacter*p2.character; SD.sum3 = p2.fortune+p2.appearance+p2.character; SD.id = p2.id; return SD; } void matching()//匹配过程 { int i = 0, j = 0, k = 0, l = 0, minID = M-1, //最小的未匹配的id号 satM2FID = -2, //男性最满意的女性的id satF2MID = -2, //女性最满意的男性的id invitedN = 0, //女性的被邀请数临时变量 matchedFID = -1, noMatchNo = M; //匹配成功的女性id号及配对数 SatDegree m2f, f2m,//男性对女性的满意度、女性对男性的满意度 satFD, satMD; //男性对女性的满意度及女性对男性的满意度的临时变量 //vector<int> atemp(M,-1), btemp(M,-1); for ( ; noMatchNo > 0; --noMatchNo) { //测试 //cout << "匹配第" << noMatchNo << "队情况:" << endl; for (i = 0; i<= M; ++i) //依次寻找未匹配男性i的最满意id号及获得对应的女性邀请数目 { if (!male[i].match && male[i].id >= -1) //male[0]存储的是主角或者空,空时不处理 { for (j = 0; j <= M; ++j) { if (female[j].id < -1)//female[0]存储的是主角或者空,空时不处理 continue; m2f = satisfy(male[i],female[j]); satm2fM[i][j] = m2f.satD; if (m2f > satFD && !female[j].match) { satM2FID = j-1; //id号是hash表序号-1 satFD = m2f; } //测试: //cout << "男性id=" << i-1 << ",女性id=" << j-1 << ",对女性的满意度" << m2f.satD << endl << endl; } ++female[satM2FID+1].satisfyID; //对应女性的被邀请数目加1 male[i].satisfyID = satM2FID; satFD.satD = 0; satFD.sum3 = 0; satFD.id = -2; //重置临时的男对女满意度 //测试: //if (noMatchNo == M) // cout << "男性id=" << i-1 << ",最喜欢的女性id=" << satM2FID << endl; } } //测试 //cout << endl << "寻找邀请数最多的女性:" << endl; for (k = 0; k <= M; ++k) //寻找邀请数最多的女性id { if (female[k].id < -1)//female[0]存储的是主角或者空,空时不处理 continue; if (!female[k].match) //k的id不小于matchedFID if ((female[k].satisfyID > invitedN) ||//k的选票大于matchedID的 ((female[k].satisfyID == invitedN) && //k的选票等于matchedID的 (sum3(female[k]) > sum3(female[matchedFID+1]))))//k的属性和大于matchedID的 { invitedN = female[k].satisfyID; matchedFID = k-1; } } invitedM[M-noMatchNo][0] = matchedFID; invitedM[M-noMatchNo][1] = invitedN; //测试 //cout << "邀请数最多的女性id=" << matchedFID << ",邀请数" << invitedN << endl // << endl << "寻找匹配的男性:" << endl; invitedN = 0; //被邀请数临时变量重置为0 for (l = 0; l <= M; ++l) //寻找匹配的男性 { if (male[l].id < -1) //male[0]存储的是主角或者空,空时不处理 continue; f2m = satisfy(female[matchedFID+1],male[l]);satf2mM[matchedFID+1][l] = f2m.satD; if (male[l].satisfyID == matchedFID && !male[l].match && f2m > satMD) { satF2MID = l-1; satMD = f2m; } } //测试 //cout << "匹配男性id=" << satF2MID << ",满意度" << satMD.satD << endl; male[satF2MID+1].match = true; male[satF2MID+1].matchID = matchedFID; satMD = 0;satMD.sum3 = 0;satMD.id = -2;//重置临时的女对男满意度 //测试 //atemp[satF2MID] = satF2MID; btemp[matchedFID] = matchedFID; //cout << noMatchNo << "," << satF2MID << "," << matchedFID << endl; minID = M; for (k = 0; k <= M; ++k)//删除未匹配的女性的邀请数且将matchedFID重置为未匹配女性中的最小id号 { if (female[k].id < -1)//female[0]存储的是主角或者空,空时不处理 continue; if (!female[k].match && k !=matchedFID+1 && female[k].satisfyID <= female[matchedFID+1].satisfyID) { female[k].satisfyID = 0; if ((k-1) < minID) minID = k-1; } } female[matchedFID+1].match = true; //删除匹配的女性 female[matchedFID+1].matchID = satF2MID; matchedFID = minID; } } int random(int x) { return rand()%x; } //随机初始化一个人的属性(ID除外) Person randPerson() { Person p; p.fortune = random(M)+1; p.appearance = random(M)+1; p.character = random(M)+1; p.wFortune = random(M-2)+1; p.wAppearance = random(M-p.wFortune)+1; p.wCharacter = M-p.wFortune-p.wAppearance; return p; } //随机生成数据、初始化并将其保存到对应的hash表中 void generateData(Person user) { vector<int> randSort1(M), randSort2(M); Person p1, p2; int i = 0; ofstream ofs1, ofs2; //任意排列0-M之间的数 for (i = 0; i<M; ++i) { randSort1[i] = i; randSort2[i] = i; } random_shuffle(randSort1.begin(),randSort1.end()); random_shuffle(randSort2.begin(),randSort2.end()); //随机生成男性和女性数据 ofs1.open("male1.txt",ios_base::out); ofs2.open("female1.txt",ios_base::out); for (i = 0; i<M; ++i) { p1 = randPerson(); p1.sex = 1;p1.id = randSort1[i]; if (1 == user.sex && 0 == randSort1[i]) //用户是男性则将其替换为生成的0号id数据 p1 = user; male[p1.id+1] = p1; ofs1 << p1.id << "," << p1 << endl; p2 = randPerson(); p2.sex = 0;p2.id = randSort2[i]; if (1 == user.sex && 0 == randSort2[i]) //用户是女性则将其替换为生成的0号id数据 p1 = user; female[p2.id+1] = p2; ofs2 << p2.id << "," << p2 << endl; } ofs1.close(); ofs2.close(); } //读入文本数据并初始化以及进行测试 void readData() { Person p1, p2; ifstream ifs1, ifs2; ifs1.open("male.txt",ios_base::in); ifs2.open("female.txt",ios_base::in); while((ifs1 >> p1) && (ifs2 >> p2)) { male[p1.id+1] = p1; female[p2.id+1] = p2; } ifs1.close(); ifs2.close(); } //将结果保存到文本文件中 void result() { int i = 0, j = 0; ofstream ofs1, ofs2, ofs3, ofs4; ofs1.open("satm2fM.txt",ios_base::out); //保存男对女的满意度矩阵 ofs2.open("satf2mM.txt",ios_base::out); //保存女对男的满意度矩阵 ofs3.open("matched.txt",ios_base::out); //保存匹配结果 ofs4.open("invitedM.txt",ios_base::out);//保存女性被邀请的最多的id号及次数 for (i = 0; i <=M; ++i) { for (j = 0; j <= M; ++j) { ofs1 << satm2fM[i][j] <<","; ofs2 << satf2mM[i][j] <<","; } ofs1 << endl << endl; ofs2 << endl << endl; } for (i = 0; i <= M; ++i) { ofs3 << i << ":" << male[i].id <<"," << male[i].matchID << endl; ofs4 << i << ":" << invitedM[i][0] <<"," << invitedM[i][1] << endl; } ofs1.close(); ofs2.close(); ofs3.close(); ofs4.close(); } //程序开始 void startProg() { char ch, //用于接收用户选项:是想测试还是直接计算 E = \'n\', //用于接收用户输入:是否退出程序 comma; int line = 0; //指定读入的行 Person user; ifstream ifs; cout << "===========数字化婚姻配对尝试仿真程序===========" << endl; cout << "主角的信息包括:性别,样貌,品格,财富,期望样貌,期望品格,期望财富:" << endl << "输入时请按该要求依次输入主角信息!" << endl << "示例1:1,80,5,29,25,62,13;示例2:0,1,99,78,84,14,2" << endl; cout << "您是想测试用例还是自己输入数据进行计算?(测试输入T/t,计算输入C/c)" << endl; cin >> ch; if (\'T\' == ch || \'t\' == ch)//测试 { ifs.open("players.txt",ios_base::in); ifs.seekg(0,ifs.end); int line_lenght = ifs.tellg()/M; //计算players.txt文件每一行的长度 while (E != \'Y\' && E != \'y\') { readData(); cout << "请输入所给用户示例文件players.txt中主角所在的行数:"; cin >> line; ifs.seekg((line-1)*line_lenght,ifs.beg); ifs >> user.sex >> comma >> user.fortune >> comma >> user.appearance >> comma >> user.character >> comma >> user.wFortune >> comma >> user.wAppearance >> comma >> user.wCharacter; user.id = -1; cout << line << "号主角的信息为:" << endl; cout << user << endl; if (1 == user.sex) //主角是男性 { male[0] = user; matching(); cout << "与主角匹配的属性值为:" << female[male[0].matchID+1] << endl; } else//主角是女性 { female[0] = user; matching(); cout << "与主角匹配的属性值为:" << male[female[0].matchID+1] << endl; } result(); cout << "是否结束?(是Y/y)或(否N/n):"; cin >> E; } ifs.close(); } else if (\'C\' == ch || \'c\' == ch) //计算 { while (E != \'Y\' && E != \'y\') { cout << "请输入主角的属性值:"; cin >> user.sex >> comma >> user.fortune >> comma >> user.appearance >> comma >> user.character >> comma >> user.wFortune >> comma >> user.wAppearance >> comma >> user.wCharacter; user.id = 0; generateData(user);//生成数据 matching(); if (1 == user.sex) //主角是男性 cout << "与主角匹配的属性值为:" << female[male[user.id+1].matchID+1] << endl; if (0 == user.sex) //主角是男性 cout << "与主角匹配的属性值为:" << male[female[user.id+1].matchID+1] << endl; result(); cout << "是否结束:是Y/y或否N/n:"; cin >> E; } } else cout << "error!" << endl; } int main() { srand((int)time(0)); startProg(); return 0; }
View Code