花了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的作者,這些坑是在研究了他的代碼邏輯之後,和我原有的邏輯進行比對之後才發現的.
最後發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