00. 目录
01. 题目要求
某市举行一场演讲比赛( speech_contest ),共有24个人参加。比赛共三轮,前两轮为淘汰赛,第三轮为决赛。
比赛方式:分组比赛,每组6个人;选手每次要随机分组,进行比赛;
第一轮分为4个小组,每组6个人。比如编号为: 100-123. 整体进行抽签(draw)后顺序演讲。当小组演讲完后,淘汰组内排名最后的三个选手,然后继续下一个
小组的比赛。
第二轮分为2个小组,每组6人。比赛完毕,淘汰组内排名最后的三个选手,然后继续下一个小组的比赛。
第三轮只剩下1组6个人,本轮为决赛,选出前三名。
比赛评分:10个评委打分,去除最低、最高分,求平均分每个选手演讲完由10个评委分别打分。
该选手的最终得分是去掉一个最高分和一个最低分,求得剩下的8个成绩的平均分。选手的名次按得分降序排列。
用STL编程,求解这个问题
1) 请打印出所有选手的名字与参赛号,并以参赛号的升序排列。
2) 打印每一轮比赛后,小组比赛成绩和小组晋级名单
02. 思路分析
需要把选手信息、选手得分信息、选手比赛抽签信息、选手的晋级信息保存在容器中,需要涉及到各个容器的选型。
选手可以设计一个类Person(姓名和得分)
所有选手的编号可以单独放在一个vector容器中,做抽签用
所有选手编号和选手信息,可以放在容器内:map<int, Person>
所有选手的编号名单,可以放在容器:vecter v1中
第1轮晋级编号名单,可以放在容器vecter v2中
第2轮晋级编号名单,可以放在容器vecter v3中
第3轮前三名名单,可以放在容器vecter v4中
每个小组的比赛得分信息,按照从大到小的顺序放在multimap<成绩, 编号, greater>中
03. 随机重排
算法:
random_shuffle
shuffle
随机重排范围中的元素
可能实现V1
template<class RandomIt>
void random_shuffle(RandomIt first, RandomIt last)
{
typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;
for (diff_t i = last - first - 1; i > 0; --i)
{
using std::swap;
swap(first[i], first[std::rand() % (i + 1)]);
// rand() % (i + 1) 实际上不准确,因为生成的数对于多数 i 值不均匀分布。
// 正确实现将实际上需要重新实现 C++11 std::uniform_distributtion,
// 这超出了此示例的范畴。
}
}
可能实现V2
template<class RandomIt, class RandomFunc>
void random_shuffle(RandomIt first, RandomIt last, RandomFunc&& r)
{
typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;
for (diff_t i = last - first - 1; i > 0; --i)
{
using std::swap;
swap(first[i], first[r(i + 1)]);
}
}
可能实现V3
template<class RandomIt, class URBG>
void shuffle(RandomIt first, RandomIt last, URBG&& g)
{
typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;
typedef std::uniform_int_distribution<diff_t> distr_t;
typedef typename distr_t::param_type param_t;
distr_t D;
for (diff_t i = last - first - 1; i > 0; --i)
{
using std::swap;
swap(first[i], first[D(g, param_t(0, i))]);
}
}
程序示例:
#include <random>
#include <algorithm>
#include <iterator>
#include <vector>
using namespace std;
int main(void)
{
random_device rd;
mt19937 g(rd());
vector<int> v {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
shuffle(v.begin(), v.end(), g);
copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
cout << endl;
return 0;
}
运行结果:
deng@local:~/code$ ./a.out
3 1 7 5 4 9 6 2 10 8
deng@local:~/code$ ./a.out
4 3 8 2 7 6 9 5 10 1
deng@local:~/code$ ./a.out
10 8 9 1 5 3 7 4 2 6
deng@local:~/code$ ./a.out
9 4 8 1 6 3 7 2 5 10
deng@local:~/code$ ./a.out
2 10 6 5 8 1 7 9 3 4
deng@local:~/code$ ./a.out
5 2 6 3 10 1 9 8 7 4
deng@local:~/code$ ./a.out
9 4 10 6 3 8 5 2 7 1
deng@local:~/code$ ./a.out
2 1 8 9 3 6 10 4 5 7
deng@local:~/code$ ./a.out
8 6 10 1 3 2 7 5 4 9
deng@local:~/code$
04. 创建选手
程序示例:
#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <map>
using namespace std;
//选手信息
class Person
{
friend int showPerson(const map<int, Person> &m);
public:
//无参构造函数
Person()
{
}
//有参构造函数
Person(int num, string name)
{
mNum = num;
mName = name;
memset(mScore, 0, 3 * sizeof(float));
}
private:
//参赛号
int mNum;
//姓名
string mName;
//得分 分别存储第1,2,3轮得分
float mScore[3];
};
//创建选手
int createPerson(vector<int> &v, map<int, Person> &m)
{
int i = 0;
string name;
string str = "ABCDEFGHIJKLMNOPQRSTUVWX";
//24个选手
for (i = 100; i < 124; i++)
{
//存放选手编号
v.push_back(i);
//选手编号和选手信息关联
name = "选手";
name += str[i - 100];
m.insert(make_pair(i, Person(i, name)));
}
return 0;
}
//显示选手
int showPerson(const map<int, Person> &m)
{
map<int, Person>::const_iterator it;
for (it = m.begin(); it != m.end(); it++)
{
cout << "选手编号: " << it->first << " 选手姓名: " << it->second.mName << endl;
}
return 0;
}
int main(void)
{
//使用vector容器存储选手编号
vector<int> v;
//使用map容器存储编号和选手的信息
map<int, Person> m;
//创建选手
createPerson(v, m);
//显示选手信息
showPerson(m);
return 0;
}
运行结果
deng@local:~/code$ g++ test.cpp
deng@local:~/code$ ./a.out
选手编号: 100 选手姓名: 选手A
选手编号: 101 选手姓名: 选手B
选手编号: 102 选手姓名: 选手C
选手编号: 103 选手姓名: 选手D
选手编号: 104 选手姓名: 选手E
选手编号: 105 选手姓名: 选手F
选手编号: 106 选手姓名: 选手G
选手编号: 107 选手姓名: 选手H
选手编号: 108 选手姓名: 选手I
选手编号: 109 选手姓名: 选手J
选手编号: 110 选手姓名: 选手K
选手编号: 111 选手姓名: 选手L
选手编号: 112 选手姓名: 选手M
选手编号: 113 选手姓名: 选手N
选手编号: 114 选手姓名: 选手O
选手编号: 115 选手姓名: 选手P
选手编号: 116 选手姓名: 选手Q
选手编号: 117 选手姓名: 选手R
选手编号: 118 选手姓名: 选手S
选手编号: 119 选手姓名: 选手T
选手编号: 120 选手姓名: 选手U
选手编号: 121 选手姓名: 选手V
选手编号: 122 选手姓名: 选手W
选手编号: 123 选手姓名: 选手X
deng@local:~/code$
05. 抽签比赛
程序示例
#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <map>
#include <deque>
#include <ctime>
#include <random>
#include <algorithm>
#include <iterator>
using namespace std;
//随机重排相关
random_device rd;
mt19937 g(rd());
//选手信息
class Person
{
friend int showPerson(const map<int, Person> &m);
friend int playGame(int index, vector<int> &v, map<int, Person> &m, vector<int> &v1);
public:
//无参构造函数
Person()
{
}
//有参构造函数
Person(int num, string name)
{
mNum = num;
mName = name;
memset(mScore, 0, 3 * sizeof(float));
}
private:
//参赛号
int mNum;
//姓名
string mName;
//得分 分别存储第1,2,3轮得分
float mScore[3];
};
//创建选手
int createPerson(vector<int> &v, map<int, Person> &m)
{
int i = 0;
string name;
string str = "ABCDEFGHIJKLMNOPQRSTUVWX";
//24个选手
for (i = 100; i < 124; i++)
{
//存放选手编号
v.push_back(i);
//选手编号和选手信息关联
name = "选手";
name += str[i - 100];
m.insert(make_pair(i, Person(i, name)));
}
return 0;
}
//显示选手
int showPerson(const map<int, Person> &m)
{
map<int, Person>::const_iterator it;
for (it = m.begin(); it != m.end(); it++)
{
cout << "选手编号: " << it->first << " 选手姓名: " << it->second.mName << endl;
}
return 0;
}
//参加比赛
//v存储参加比赛的选手编号, m存储选手信息 v1存储晋级选手编号
int playGame(int index, vector<int> &v, map<int, Person> &m, vector<int> &v1)
{
int count = 0;
int i = 0;
//平均分
float avg = 0;
//存储选手得分
deque<int> d;
//存储分数和编号
multimap<float, int, greater<float>> mul;
//随机重排选手
shuffle(v.begin(), v.end(), g);
#if 0
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
#endif
cout << "-------------第" << index << "轮比赛-----------" << endl;
//每6人一组
vector<int>::iterator it;
for (it = v.begin(); it != v.end(); it++)
{
count++;
//10评委评分
for (i = 0; i < 10; i++)
{
d.push_back((float)(random() % 80 + 21));
}
//对容器进行排序
sort(d.begin(), d.end());
//去掉最高分和最低分
d.pop_back();
d.pop_front();
//计算平均分
avg = accumulate(d.begin(), d.end(), 0) / d.size();
//将选手得分保存到容器中
m[*it].mScore[index - 1] = avg;
//存储选手编号和得分
mul.insert(make_pair(avg, *it));
//刚好每6人一组
if (0 == count % 6)
{
multimap<float, int, greater<float>>::iterator mit;
int j = 0;
//将前3名存储到晋级容器中
mit = mul.begin();
for (j = 0; j < 3; j++, mit++)
{
v1.push_back(mit->second);
}
cout << "\t------------第" << count / 6 << "组的成绩---------------" << endl;
//遍历当前容器中所有人员的成绩
for (mit = mul.begin(), j = 0; j < 6; j++, mit++)
{
cout << "\t\t" << m[mit->second].mName << " 编号: " << mit->second
<< " 成绩: " << mit->first;
if (j < 3)
{
cout << "恭喜晋级" << endl;
}
else
{
cout << endl;
}
}
//清空容器
mul.clear();
}
}
return 0;
}
int main(void)
{
//设置随机种子
srandom(time(NULL));
//使用vector容器存储选手编号
vector<int> v;
//使用map容器存储编号和选手的信息
map<int, Person> m;
//存储第一轮晋级名单
vector<int> v1;
//存储第二轮晋级名单
vector<int> v2;
//存储第二轮晋级名单
vector<int> v3;
//创建选手
createPerson(v, m);
//显示选手信息
showPerson(m);
cout << "====================================================" << endl;
playGame(1, v, m, v1);
cout << "====================================================" << endl;
playGame(2, v1, m, v2);
cout << "====================================================" << endl;
playGame(3, v2, m, v3);
return 0;
}
运行结果
deng@local:~/code$ ./a.out
选手编号: 100 选手姓名: 选手A
选手编号: 101 选手姓名: 选手B
选手编号: 102 选手姓名: 选手C
选手编号: 103 选手姓名: 选手D
选手编号: 104 选手姓名: 选手E
选手编号: 105 选手姓名: 选手F
选手编号: 106 选手姓名: 选手G
选手编号: 107 选手姓名: 选手H
选手编号: 108 选手姓名: 选手I
选手编号: 109 选手姓名: 选手J
选手编号: 110 选手姓名: 选手K
选手编号: 111 选手姓名: 选手L
选手编号: 112 选手姓名: 选手M
选手编号: 113 选手姓名: 选手N
选手编号: 114 选手姓名: 选手O
选手编号: 115 选手姓名: 选手P
选手编号: 116 选手姓名: 选手Q
选手编号: 117 选手姓名: 选手R
选手编号: 118 选手姓名: 选手S
选手编号: 119 选手姓名: 选手T
选手编号: 120 选手姓名: 选手U
选手编号: 121 选手姓名: 选手V
选手编号: 122 选手姓名: 选手W
选手编号: 123 选手姓名: 选手X
====================================================
-------------第1轮比赛-----------
------------第1组的成绩---------------
选手D 编号: 103 成绩: 65恭喜晋级
选手J 编号: 109 成绩: 62恭喜晋级
选手F 编号: 105 成绩: 61恭喜晋级
选手G 编号: 106 成绩: 59
选手I 编号: 108 成绩: 58
选手U 编号: 120 成绩: 57
------------第2组的成绩---------------
选手B 编号: 101 成绩: 60恭喜晋级
选手K 编号: 110 成绩: 59恭喜晋级
选手N 编号: 113 成绩: 58恭喜晋级
选手H 编号: 107 成绩: 58
选手W 编号: 122 成绩: 57
选手V 编号: 121 成绩: 56
------------第3组的成绩---------------
选手L 编号: 111 成绩: 61恭喜晋级
选手X 编号: 123 成绩: 60恭喜晋级
选手R 编号: 117 成绩: 60恭喜晋级
选手T 编号: 119 成绩: 59
选手S 编号: 118 成绩: 59
选手P 编号: 115 成绩: 58
------------第4组的成绩---------------
选手E 编号: 104 成绩: 61恭喜晋级
选手M 编号: 112 成绩: 61恭喜晋级
选手Q 编号: 116 成绩: 61恭喜晋级
选手O 编号: 114 成绩: 61
选手C 编号: 102 成绩: 61
选手A 编号: 100 成绩: 61
====================================================
-------------第2轮比赛-----------
------------第1组的成绩---------------
选手D 编号: 103 成绩: 70恭喜晋级
选手N 编号: 113 成绩: 64恭喜晋级
选手X 编号: 123 成绩: 63恭喜晋级
选手Q 编号: 116 成绩: 61
选手B 编号: 101 成绩: 57
选手F 编号: 105 成绩: 57
------------第2组的成绩---------------
选手L 编号: 111 成绩: 62恭喜晋级
选手R 编号: 117 成绩: 61恭喜晋级
选手E 编号: 104 成绩: 60恭喜晋级
选手K 编号: 110 成绩: 60
选手J 编号: 109 成绩: 59
选手M 编号: 112 成绩: 58
====================================================
-------------第3轮比赛-----------
------------第1组的成绩---------------
选手L 编号: 111 成绩: 64恭喜晋级
选手D 编号: 103 成绩: 58恭喜晋级
选手R 编号: 117 成绩: 58恭喜晋级
选手N 编号: 113 成绩: 57
选手X 编号: 123 成绩: 57
选手E 编号: 104 成绩: 56
deng@local:~/code$
06. 讨论
07. 附录
中文cppreference社区地址:http://zh.cppreference.com/w/Main_Page
英文cppreference社区地址:https://en.cppreference.com/w/Main_Page
cppreference社区FAQ:https://zh.cppreference.com/w/Cppreference:FAQ