花了4天时间实现了刘汝佳紫书上的例题5-10,也就是UVA207,修改了5版才AC.这里把遇到的坑说一下,供后来者参考
1、业余选手只参与排名,不参与分奖金,所以哪怕一个业余选手和其他职业选手同分(从而名次相同),也不输出T
2、只有在同一个分数两名或者更多职业选手平分奖金时,这些职业选手的名次后面才输出T,算,所以对没获奖的名次,有多少人并列都不输出T,也就是输出T的条件是本名次的获奖人数>=2
3、职业选手有奖金的条件相当于先去掉所有业余选手之后重新进行排名,如果这个新排名小于等于70(包括和第70名并列的情况)就一定有奖,哪怕对应的奖金比例是0,那么奖金那一列也要输出0,否则奖金那一列无输出
4,对于没有奖金或者犯规的选手,输出完总分之后,这一行就结束了,后面不能再输出多余的空格
还要感谢http://www.cnblogs.com/MengLan/p/5360695.html的作者,这些坑是在研究了他的代码逻辑之后,和我原有的逻辑进行比对之后才发现的.
5.对名次并列的非犯规选手,按姓名排序
6.犯规选手的输出也是有顺序的: 首先轮次多的在前,其次总分低的列前,最后才按姓名排序
最后发AC代码
#if 1
#include <iostream>
#include <iomanip>
#include <cassert>
#include <list>
#include <cctype>
#include <climits>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <iterator>
#include <stack>
#include <string>
#include <functional>
#include <utility>
#include <sstream>
#ifdef _DEBUG
#include <fstream>
#endif // _DEBUG
using namespace std;
#ifdef _DEBUG
ifstream ifs;
ofstream ofs;
const int UVA_PROBLEM_NO = 207;
void redirect_input()
{
ostringstream oss;
oss << "uva" << UVA_PROBLEM_NO << "_in.txt";
ifs.open(oss.str().c_str());
cin.rdbuf(ifs.rdbuf());
}
void redirect_output()
{
ostringstream oss;
oss << "uva" << UVA_PROBLEM_NO << "_out.txt";
ofs.open(oss.str().c_str());
cout.rdbuf(ofs.rdbuf());
}
#endif
const int MAX_CUT_RANK = 70; //最多录取70个人
const int MAX_PRIZE_RANK = 70; //最多录取70个人
const int MAX_ROUND_NUM = 4;
const double eps = 1e-8; //用来控制输出精度
//删除字符串前后的空格,替换掉原来的字符串
void skip(string & str)
{
size_t L = str.size();
size_t pos1 = 0;
//定位到第一个空白字符
while (pos1 < L && isspace(str[pos1]))
++pos1;
//定位到最后一个非空白字符
size_t pos2 = L - 1;
while (pos2 >= 0 && isspace(str[pos2]))
--pos2;
if (pos1 > 0 || pos2 < L - 1)
str = str.substr(pos1, pos2 - pos1 + 1);
}
void main_proc();
int main() {
#ifdef _DEBUG
redirect_input();
redirect_output();
#endif // _DEBUG
main_proc();
#ifdef _DEBUG
ifs.close();
ofs.close();
#endif
return 0;
}
//晋级选手的信息
struct Player {
string name;
bool amateur; //本人是否为业余选手
vector<int> scores; //每轮得分,-1表示本轮犯规
int dq; //记录哪一轮有犯规情形,没有犯规则值为则为最大轮次数,对晋级选手,决赛时如果出现法规不能获奖,但是要输出到晋级名单中,
int cut_total_score; //晋级时的总分(即前两轮总分之和)
int total_score; //总得分,有犯规的话输出DQ,实际操作时,先记录前两轮的得分,然后记录后两轮的得分
int cut_rank; //晋级时的排名
int final_rank; //选手的决赛排名
bool tie; //本名次是否有并列获奖的情况
double prize; //最后获得的奖金
bool have_prize; //是否获奖
Player()
:amateur(false)
, scores(4)
, dq(MAX_ROUND_NUM)
, cut_total_score(0)
, total_score(0)
, cut_rank(0)
, final_rank(0)
, tie(false)
, prize(0)
, have_prize(false)
{
}
Player(const Player& other)
:name(other.name)
, amateur(other.amateur)
, scores(other.scores)
, dq(other.dq)
, cut_total_score(other.cut_total_score)
, total_score(other.total_score)
, cut_rank(other.cut_rank)
, final_rank(other.final_rank)
, tie(other.tie)
, prize(other.prize)
,have_prize(other.have_prize)
{
}
void read()
{
string line;
getline(cin, line);
name = line.substr(0, 20);
amateur = (name.find('*') != string::npos);
size_t pos = 20;
/*
Characters 1–20: Player name
Characters 21–23: Round 1 score (first 18 holes)
Characters 24–26: Round 2 score (second 18 holes)
Characters 27–29: Round 3 score (third 18 holes)
Characters 30–32: Round 4 score (fourth 18 holes)
*/
for (int i = 0;i < MAX_ROUND_NUM;++i, pos += 3)
{
const string& str = line.substr(pos, 3);
if (str.find("DQ") != string::npos)
{
dq = i;
break;
}
else {
istringstream iss(str);
iss >> scores[i];
}
}
}
//输出晋级时的信息
void print_cut_detail()const {
string namestr = name;
cout << setw(21) << left << name;
cout << setw(10) << left << cut_rank;
for (int i = 0;i < MAX_ROUND_NUM;++i)
{
cout << setw(5) << left;
if (i >= dq)
cout << " ";
else
cout << scores[i];
}
cout << setw(10) << left << cut_total_score;
cout << endl;
}
void print_final_detail()const
{
cout << setw(21) << left << name;
{
ostringstream oss;
if (dq == MAX_ROUND_NUM)
{
oss << final_rank;
if (tie)
oss << "T";
}
cout << setw(10) << left << oss.str();
}
for (int i = 0;i < MAX_ROUND_NUM;++i)
{
cout << setw(5) << left;
if (i >= dq)
cout << " ";
else
cout << scores[i];
}
if (dq<MAX_ROUND_NUM)
{
cout << "DQ";
}
else {
if (!have_prize)
cout << left << total_score;
else
{
cout << setw(10) << left << total_score;
cout << "$";
{
ostringstream oss;
oss << setprecision(2) << fixed << (prize / 100.0);
cout << setw(9) << right << oss.str();
}
}
}
cout << endl;
}
};
struct PGATour
{
list<Player> players; //录取的选手的列表
list<Player> dq_players; //犯规的选手列表
vector<double> prize_per; //每个名次可以获得的奖金比例
double total_prize;
PGATour()
:prize_per(MAX_PRIZE_RANK)
{
}
//读取奖金和选手信息
void read()
{
cin >> total_prize;
for (int i = 0;i < MAX_PRIZE_RANK;++i)
{
cin >> prize_per[i];
}
int player_num = 0;
cin >> player_num;
cin.ignore(2, '\n');
for (int i = 0;i < player_num;++i)
{
Player player;
player.read();
//player.print_cut_detail();
//如果选手前两轮没有犯规,才有可能晋级
if (player.dq > 1) {
players.push_back(player);
}
}
}
//录取预赛成绩最好的70个选手晋级
void make_cut()
{
for (auto& e : players)
{
e.cut_total_score = e.scores[0] + e.scores[1];
}
//进行排序
players.sort([](const Player& p1, const Player& p2) {
return p1.cut_total_score < p2.cut_total_score;
});
int cur_rank = 1;
int last_cut_total_score = -1;
int n = 0;
//录取前70个人
auto it = players.begin();
for (;it != players.end();++it)
{
++n;
Player& player = *it;
//不并列的话新的当前名次就是n
if (player.cut_total_score != last_cut_total_score)
cur_rank = n;
if (cur_rank > MAX_CUT_RANK)
break;
else {
player.cut_rank = cur_rank;
last_cut_total_score = player.cut_total_score;
}
}
//删除70名之后的
players.erase(it, players.end());
}
//输出预赛晋级选手
void print_cut()const
{
cout << "Player Name Place RD1 RD2 RD3 RD4 TOTAL "
<< endl;
cout << string(62, '-')
<< endl;
for (auto& e : players)
{
e.print_cut_detail();
}
}
void print_final()const
{
cout << "Player Name Place RD1 RD2 RD3 RD4 TOTAL Money Won"
<< endl;
cout << string(71, '-')
<< endl;
for (auto e : players)
{
e.print_final_detail();
}
for (auto e : dq_players)
{
e.print_final_detail();
}
}
void get_dq_list()
{
auto it = players.begin();
while (it != players.end())
{
if (it->dq < MAX_ROUND_NUM)
{
dq_players.push_front(*it);
it = players.erase(it);
}
else
++it;
}
dq_players.sort([](const Player& p1, const Player& p2) {
if (p1.dq != p2.dq)
return p1.dq > p2.dq;
else if (p1.total_score != p2.total_score)
return p1.total_score < p2.total_score;
else
return p1.name < p2.name;
});
}
void get_final_rank()
{
players.sort([](const Player& p1, const Player& p2) {
return (p1.total_score < p2.total_score) ||
(p1.total_score == p2.total_score && p1.name < p2.name);
});
int n = 0;
int last_total_score = -1;
int cur_rank = 0;
for (auto & e : players)
{
++n;
if (e.total_score != last_total_score)
cur_rank = n;
e.final_rank = cur_rank;
last_total_score = e.total_score;
}
}
//为每个选手分配奖金
void allocate_prize() {
int pos = 0;
for (auto it1 = players.begin(); it1 != players.end();)
{
if (pos >= MAX_PRIZE_RANK)
break;
//统计本分数段的获奖人数数目
int n = 0;
auto it2 = it1;
for (
;it2 != players.end()
;++it2)
{
if (it2->total_score != it1->total_score)
break;
if (!it2->amateur)
++n;
}
if (n>0)
{
double total_per = 0;
for (int i=0;i<n &&pos<MAX_PRIZE_RANK;++i,++pos)
total_per += prize_per[pos];
double prize = total_prize * total_per / n; //计算每个人的奖金
//为本分数段的每个人颁奖
for ( ;it1 != it2;++it1){
if (!it1->amateur)
{
it1->tie = n>1;
it1->prize = prize;
it1->have_prize = true;
}
}
}
else
it1 = it2;
}
}
//排出决赛名次
void final_match()
{
//计算每个人在犯规那一轮之前的总分
for (auto &e : players)
{
e.total_score = 0;
for (int i = 0;i < e.dq;++i)
e.total_score += e.scores[i];
}
get_dq_list();
get_final_rank();
allocate_prize();
}
};
void main_proc()
{
int case_num;
cin >> case_num;
for (int i = 0;i < case_num;++i)
{
if (i > 0)
cout << endl;
PGATour tour;
tour.read();
tour.make_cut();
//tour.print_cut();
tour.final_match();
tour.print_final();
}
}
#endif