需求:
某学校举行一场唱歌比赛,共有24个人参加,按参加顺序设置参赛号(参赛号为100至123)。
每个选手唱完一首歌之后,由10个评委分别打分。该选手的最终得分是去掉一个最高分和一个最低分,求得剩下的8个评分的平均分。
比赛共三轮,前两轮为淘汰赛,第三轮为决赛。选手的名次按得分降序排列,若得分一样,按参赛号升序排名。
第一轮分为4个小组,根据参赛号顺序依次划分,比如100-105为一组,106-111为第二组,依次类推,每组6个人,每人分别按参赛号
顺序演唱。当小组演唱完后,淘汰组内排名最后的三个选手,然后继续下一个小组的比赛。
第二轮分为2个小组,每组6人,每个人分别按参赛号顺序演唱。当小组演唱完后,淘汰组内排名最后的三个选手,然后继续下一个小组的比赛。
第三轮只剩下6个人,本轮为决赛,不淘汰选手,本轮目的是赛出每个人的名次。该6人按参赛号顺序分别演唱。
#include "stdafx.h"
#include "stdio.h"
#include "string"
#include "vector"
#include "list"
#include "map"
#include "set"
#include "stack"
#include "deque"
#include <algorithm>//排序算法
#include "iostream"
#include <time.h>
#include <numeric>//求和函数
using namespace std;
/*
需求1、请打印出所有选手的名字与参赛号,并以参赛号的升序排列。
分析1、参赛号唯一,可以用map,参加比赛的时候对map进行赋值
需求2、请打印出第1轮和第2轮淘汰赛中,各小组选手的名字与选手得分,并以名次的顺序排列
分析2、选手和得分又是关联的,分数有可能一样,可以考虑用multimap,需要定义两个multimap,或者局部变量
流程是:分组,歌唱,评分,打印,更新list
分组:按照需要分组,6人一组,每一轮比赛流程一致,可以统一写成一个函数
伪代码:
Round = 1
start = 100
歌手IDlist来控制循环每一个歌手进行比赛
for i = 0,i < 6,i++
index = start + i
//唱歌:用Singer对象调用唱歌方法
//评分:获取10的随机评分值(??),用临时变量deque来做记录,sort排序一下,去掉最高和最低,然后求和平均,把平均分与这个歌手绑定 multimap
//歌手和分数绑定,分数有可能一样,用multimap
endfor
//map自动排序,打印出这一组的选手的名字和得分
//根据得分,获取晋级的和被淘汰的,把被淘汰的歌手名字用vector来存放
更新list
更新
需求3、请打印出第1轮淘汰赛中被淘汰的歌手的名字(不要求打印顺序)。
在需求2的基础上,把每组最低分的3个取出来,打印出来,更新list
需求4、请打印出第2轮淘汰赛中被淘汰的歌手的分数,并以名次的降序排列。
在需求2的基础上,把每组最低分的3个取出来,打印出来,更新list
*/
//歌手类
class Singer /*: public Ponsen*/
{
public:
Singer() { m_SingerID = 0; m_LastScore = 0;
printf("Singer Singer() GetName:%s,GetAddress:%s \n", GetName().c_str(), GetAddress().c_str());
printf("\n");
}
Singer(string name, string addr, int id) :/*Ponsen(name, addr), */m_Name(name), m_Address(addr), m_SingerID(id) { m_LastScore = 0;
printf("Singer GetName:%s, GetAddress:%s GetSingerID() = %d \n", GetName().c_str(), GetAddress().c_str(), m_SingerID);
printf("\n");
}
Singer(const Singer & sing);
inline void SingSong() {
//printf("**歌手:%s, ID:%d 唱歌*********,最终得分为%d \n", GetName().c_str(), m_SingerID , m_LastScore);
}
inline int GetSingerID() const { return m_SingerID; }
inline void SetSingerID(const int id) { m_SingerID = id; }
inline int GetScore() const{ return m_LastScore; }
inline void SetScore(const int score) { m_LastScore = score; }
inline string GetName() const { return m_Name; }
inline string GetAddress() const { return m_Address; }
inline void SetName(const string name)
{ m_Name = name; printf("Singer SetName(string) m_Name = %s \n", m_Name.c_str()); printf("\n"); }
inline void SetAddress(const string addr)
{ m_Address = addr; printf("Singer SetAddress(string) m_Address = %s \n", m_Address.c_str()); printf("\n"); }
private:
int m_SingerID;//歌手ID,唯一性
int m_LastScore;//最新分数
string m_Name;
string m_Address;
};
Singer::Singer(const Singer & sing)
{
//printf("Singer Singer(Singer&) GetName:%s,GetAddress:%s \n", GetName().c_str(), GetAddress().c_str());
printf("\n");
}
//比赛类
/*
数据结构和流程怎么设计
利用STL中的容器和算法:vector,deque,quque,stack,list,map,multimap,set,multiset
方法:
1、报名:把ID和歌手类映射一起,把ID存放到list列表中
2、分组
3、比赛(1轮,2轮,决赛):传入ID信息,
4、打印
*/
class SongCompetition
{
public:
//
SongCompetition()
{
//还没开始比赛,比赛轮数设置为0
m_iRound = 0;
//设置随机种子
srand((unsigned)time(0));
}
void SignUp(const int, const int);
//构造函数
void SignUpConpetition(const int, const Singer&);
void FirstRound();
void SecondRound();
void LastRound();
private:
int m_iRound;//比赛次数,控制比赛流程
//为什么选用map,歌手id唯一性,id与歌手的关联性
map<int, Singer, less<int>> m_SignUpInfoMap;//报名信息的Map,用一个ID绑定一个歌手
list<int> m_SingerList;//维护参赛ID,开始24人,每一轮比赛后删除淘汰的选手,然后再
multimap<int, int, greater<int>> m_mltmapCurGroupInfo;//分数,ID,降序排列,
vector<int> m_vecEliminateSingerRO;//第一轮比赛淘汰的ID号
multiset<int> m_mtlsetEliminateSingerRT;//第二轮淘汰的ID号,需要顺序
void PrintCurRoundInfo();
void RecordEliminateSinger();
void DelCurRoundSingerID(list<int>::iterator);
//唱歌得出分数函数
int SingleSongCp(Singer &);
void SingRound();
int MakeScore(const int id);
void PrintAllSignUpInfo();
};
void SongCompetition::FirstRound()
{
if (m_iRound == 0)
{
m_iRound = 1;
printf("**第%d轮歌唱比赛** \n", m_iRound);
SingRound();
//打印被淘汰的歌手的名字,由ID进行绑定
for (vector<int>::iterator it = m_vecEliminateSingerRO.begin(); it != m_vecEliminateSingerRO.end(); it++)
{
printf("被淘汰的歌手的名字为:%s \n", m_SignUpInfoMap[*it].GetName().c_str());
}
}
}
void SongCompetition::SecondRound()
{
if (m_iRound == 1)
{
m_iRound = 2;
printf("\n");
printf("**第%d轮歌唱比赛** \n", m_iRound);
SingRound();
//打印第2轮被淘汰的歌手的分数,按照顺序排列
for (multiset<int>::iterator it = m_mtlsetEliminateSingerRT.begin(); it != m_mtlsetEliminateSingerRT.end(); it++)
{
printf("被淘汰的歌手的分数:%d \n", *it);
}
}
}
void SongCompetition::LastRound()
{
if (m_iRound == 2)
{
m_iRound = 3;
printf("\n");
printf("**第%d轮歌唱比赛** \n", m_iRound);
SingRound();
}
m_SignUpInfoMap.clear();
m_SingerList.clear();
m_mltmapCurGroupInfo.clear();
m_vecEliminateSingerRO.clear();
m_mtlsetEliminateSingerRT.clear();
m_iRound = 0;
}
//在剩余歌手中删除歌手
void SongCompetition::DelCurRoundSingerID(list<int>::iterator it)
{
//输入的是ID的迭代器,通过ID号查找当前分数-ID集合中的集合,
int index = 0;//逆向遍历的索引
while (index < 6)//为什么是循环6次,
{
//查找逆向遍历迭代器所指的参赛ID所对应歌手的{分数,参赛ID}是否在当前演唱小组中
multimap<int, int, greater<int>>::iterator itr =
find(m_mltmapCurGroupInfo.begin(),
m_mltmapCurGroupInfo.end(),
multimap<int, int, greater<int>>::value_type(m_SignUpInfoMap[*it].GetScore(), *it));
index++;
if (itr == m_mltmapCurGroupInfo.end())
{
//没找到,从剩余歌手集合中删除该歌手的参赛号,因为这个歌手已经被淘汰了,要更新list列表
it = m_SingerList.erase(it);//一定要用it接收返回值,返回值为下一个迭代器
}
//防止对容器的begin()迭代器进行--操作。
if (it != m_SingerList.begin())
{
--it;
}
}
m_mltmapCurGroupInfo.clear();
}
/*
//函数功能:往map里面插入数据
*/
void SongCompetition::SignUpConpetition(const int id, const Singer &sing)
{
////插入数据方法一,//用这个方法,遍历的时候GetName内容为空,GetAddress内容为空,为什么呢
//m_SignUpInfoMap.insert(map<int, Singer>::value_type(id, sing));
//插入数据方法二,用这个方法,遍历的时候GetName内容为空,GetAddress内容为空,为什么呢
//m_SignUpInfoMap.insert(pair<int, Singer>(id, sing));
m_SignUpInfoMap[id] = sing;//插入数据方法三
printf("\n");
}
void SongCompetition::PrintCurRoundInfo()
{
if (m_mltmapCurGroupInfo.size())
{
//printf("*****************第%组比赛结果如下*************** \n", m_iRound);
for (multimap<int, int, greater<int>>::iterator it = m_mltmapCurGroupInfo.begin(); it != m_mltmapCurGroupInfo.end(); it++)
{
//根据ID号找到歌手名字
printf("歌手:%s, 歌唱评分为:%d \n", m_SignUpInfoMap[it->second].GetName().c_str(), it->first);
}
printf("\n");
}
}
void SongCompetition::SignUp(const int start, const int all)
{
for (int i = 1; i <= all; i++)
{
char strstart = 'A';//
string sFirstName(2, strstart + i);
//printf("sFirstName:%s \n", sFirstName.c_str());
Singer sing(sFirstName, "beijing", start + i);
sing.SetSingerID(start + i);
SignUpConpetition(start + i, sing);
m_SingerList.push_back(start + i);
printf("\n");
}
PrintAllSignUpInfo();
//Ponsen的属性无法设置//////////////////////////////////////////////////////////////////////////////////////////////////
}
//分组
//定义接口:唱歌比赛函数,输入ID,得出分数
int SongCompetition::SingleSongCp(Singer &sing)
{
if (1/*sing.GetSingerID > 100*/)
{
//printf("歌手%s ID:%d 准备唱歌", sing.GetName().c_str(), sing.GetSingerID());
int ret = MakeScore(sing.GetSingerID());
sing.SetScore(ret);
sing.SingSong();
return ret;
}
else
{
return 0;
}
}
//唱歌评分
int SongCompetition::MakeScore(const int id)
{
deque<int> deqSingScore;
//十个评委分别对歌手打分
for (int i = 0; i<10; ++i)
{
int iScore = 60 + rand() % 40;
deqSingScore.push_back(iScore);
//printf("评委%d对歌手%d进行评分,分数为:%d", i, id, iScore);
}
//排序sort
sort(deqSingScore.begin(), deqSingScore.end());
//排除最高和最低分
deqSingScore.pop_front();
deqSingScore.pop_back();
//求和
int sum = accumulate(deqSingScore.begin(), deqSingScore.end(), 0);
//求平均分
return sum / deqSingScore.size();
}
void SongCompetition::RecordEliminateSinger()
{
int index = 0;
//已经排好序,直接拿最后三个数据
for (int i = 0; i < 3/*m_mltmapCurGroupInfo.size() / 2*/; i++)
{
multimap<int, int, greater<int>>::iterator itr = m_mltmapCurGroupInfo.end();
--itr;
if(m_iRound == 1)
m_vecEliminateSingerRO.push_back((itr)->second);//第一轮被淘汰的ID
if (m_iRound == 2)
m_mtlsetEliminateSingerRT.insert((m_SignUpInfoMap.at(itr->second).GetScore()));//第二轮淘汰的分数
//被淘汰的ID号为
//printf("**被淘汰的歌手的ID号为:%d \n", (itr)->second);
m_mltmapCurGroupInfo.erase(itr);//删掉这个被淘汰的,剩下晋级的要用于维护list歌手列表
}
}
void SongCompetition::SingRound()
{
//m_iRound = 1;
int iSingerIndex = 0;
//printf("***********进行第%d轮唱歌比赛************** \n", m_iRound);
//参数选手信息
if (m_SingerList.size() > 0)
{
for (list<int>::iterator it = m_SingerList.begin(); it != m_SingerList.end();)
{
int ret = SingleSongCp(m_SignUpInfoMap[*it]);
m_mltmapCurGroupInfo.insert(pair<int, int>(ret, *it));//获取当前组的分数,ID
if ((++iSingerIndex) % 6 == 0)//分组从1开始,1-6,7-12
{
//这里是统计一个组的结果,分数排序,筛选,存放结果
printf("\n");
//排列当前组的名次
PrintCurRoundInfo();//打印信息:
if (m_iRound < 3)
{
RecordEliminateSinger();
DelCurRoundSingerID(it++);
}
else
{
it++;
}
}
else
{
++it;
}
}
}
}
//按照ID升序打印所有参赛选手信息
void SongCompetition::PrintAllSignUpInfo()
{
if (m_SignUpInfoMap.size())
{
for (map<int, Singer>::iterator it = m_SignUpInfoMap.begin(); it != m_SignUpInfoMap.end(); it++)
{
//pair<int, Singer> pr = *it;//用这个方法,GetName内容为空,GetAddress内容为空,为什么呢
printf("**参赛选手-编号:%d,姓名:%s, 地址:%s \r\n", it->first, it->second.GetName().c_str(), it->second.GetAddress().c_str());
}
}
}
int main()
{
SongCompetition m_SongCp;
m_SongCp.SignUp(100, 24);
m_SongCp.FirstRound();
m_SongCp.SecondRound();
m_SongCp.LastRound();
char inputchar;
cin >> inputchar;
return 0;
}