题意:
读入各个球队的名字, 和球队之间比赛的进球数, 要求统计各个球队的比赛总场数, 总得分等信息, 按以下优先级顺序进行输出:
1. 最高得分
2. 最多胜利场次
3. 最多净胜球数(进球-失球)
4. 最多进球数
5. 最少比赛场数
6. 球队名字典序, 小的排前面(比较时不区分大小写)
注意: scored 3 goals 指的是进球数为 3, 不是得分 3; 看题目的时候这个理解错了, 纠结了好久, 无从下手.
思路:
1. 读入一行, 按 # 拆分出球队名和进球数.
2. 计算得分, 净胜球等信息.
3. 根据重载的 > 进行排序, 比较规则如题意所示.
4. 按顺序进行输出.
要点:
1. 重载 > 可以是成员函数, 重载 << 时必须是友元函数, 因为其要接收一个 ostream& 的参数. ???
2. 对于 if, for, 如果想不写{}, 那么其一行写完的句子必须简短到可以直接补在 if, for 后面, 形成一行.
代码:
# include <iostream>
# include <string>
# include <cstdio>
# include <cstring>
# include <vector>
# include <algorithm>
# include <cctype>
# include <iterator>
# include <assert.h>
# include <map>
using namespace std;
// scored 3 goals 指的是进球数为 3, 不是得分 3
// 遍历 map
// 重载 <, <<(只支持 friend?)
// distance 取两个 iterator 之间的距离
class TeamRecord {
public:
TeamRecord(const string& teamName):
scoreWin_(3), scoreTie_(1), scoreLoss_(0) {
teamName_ = teamName;
teamNameUpper_ = teamName_;
transform(teamName_.begin(), teamName_.end(),
teamNameUpper_.begin(), ::toupper);
win_ = 0;
tie_ = 0;
loss_ = 0;
goalScored_ = 0;
goalAgainst_ = 0;
}
// 羸、平、输
void win() { ++win_; }
void tie() { ++tie_; }
void loss() { ++loss_; }
// 进、丢球数
void scored(const int goal) { goalScored_ += goal; }
void against(const int goal) { goalAgainst_ += goal; }
// 总分数
int getPoints() const {
return win_*scoreWin_ + tie_*scoreTie_ + loss_*scoreLoss_;
}
int getWin() const { return win_; }
int getGoalDifference() const { return goalScored_ - goalAgainst_; }
int getGoalScored() const { return goalScored_; }
int getNumGames() const { return win_ + tie_ + loss_; }
string getTeamNameUpper() const { return teamNameUpper_; }
// 转成题目需要的输出
friend ostream& operator<<(ostream& os, const TeamRecord& tr);
// 重载 > 符号, 按以下规则
/*
Most points earned.
Most wins.
Most goal difference (i.e. goals scored - goals against)
Most goals scored.
Less games played.
Lexicographic order.
*/
bool operator> (const TeamRecord& right) const {
if (getPoints() > right.getPoints()) return true;
if (getPoints() < right.getPoints()) return false;
if (getWin() > right.getWin()) return true;
if (getWin() < right.getWin()) return false;
if (getGoalDifference() > right.getGoalDifference()) return true;
if (getGoalDifference() < right.getGoalDifference()) return false;
if (getGoalScored() > right.getGoalScored()) return true;
if (getGoalScored() < right.getGoalScored()) return false;
// 这里是不同的,要参赛参少的排前面
if (getNumGames() < right.getNumGames()) return true;
if (getNumGames() > right.getNumGames()) return false;
// 名字比较时不区分大小写, 按字典序,小的排前面
return (getTeamNameUpper() < right.getTeamNameUpper());
}
private:
string teamName_;
string teamNameUpper_;
int win_;
int tie_;
int loss_;
int goalScored_ ; // 进球数
int goalAgainst_; // 丢球数
const int scoreWin_; // 羸了 3 分
const int scoreTie_; // 平了 1 分
const int scoreLoss_; // 输了 0 分
};
ostream& operator<<(ostream& os, const TeamRecord& tr) {
char temp[500];
sprintf(temp, "%s %dp, %dg (%d-%d-%d), %dgd (%d-%d)",
tr.teamName_.c_str(),
tr.getPoints(),
tr.win_ + tr.tie_ + tr.loss_,
tr.win_,
tr.tie_,
tr.loss_,
tr.goalScored_ - tr.goalAgainst_,
tr.goalScored_,
tr.goalAgainst_);
os << temp;
return os;
}
// 比较两个 TeamRecord
bool greaterRank(const TeamRecord* tr1, const TeamRecord* tr2) {
return (*tr1) > (*tr2);
}
// 将 Brazil#2@1#Scotland 格式中的 teamName, goals 分解出来
void splitTeamGoals(const string& line,
map<string, TeamRecord*>& teamRecords) {
size_t pos1 = line.find("#", 0);
size_t pos2 = line.find("@", 0);
size_t pos3 = line.find("#", pos2);
string teamName1 = line.substr(0, pos1);
int goals1 = atoi(line.substr(pos1+1, pos2-pos1-1).c_str());
string teamName2 = line.substr(pos3+1, line.size()-pos3-1);
int goals2 = atoi(line.substr(pos2+1, pos3-pos2-1).c_str());
TeamRecord* tr1 = teamRecords[teamName1];
TeamRecord* tr2 = teamRecords[teamName2];
if (goals1 > goals2) { // 羸
tr1->win();
tr2->loss();
} else if (goals1 < goals2) { // 负
tr1->loss();
tr2->win();
} else { // 平
tr1->tie();
tr2->tie();
}
// 进球记录
tr1->scored(goals1);
tr1->against(goals2);
tr2->scored(goals2);
tr2->against(goals1);
}
int main(int argc, char const *argv[])
{
#ifndef ONLINE_JUDGE
freopen("10194_i.txt", "r", stdin);
freopen("10194_o.txt", "w", stdout);
#endif
int numTournament;
cin >> numTournament;
cin.ignore(); // cin 后接 getline, 一定要有这个
while (numTournament--) {
string tournamentName;
getline(cin, tournamentName);
cout << tournamentName << endl;
// 读入球队名
int numTeams;
cin >> numTeams;
cin.ignore();
vector<string> teamNames;
map<string, TeamRecord*> teamRecords;
while (numTeams--) {
string teamName;
getline(cin, teamName);
teamNames.push_back(teamName);
TeamRecord* tr = new TeamRecord(teamName);
teamRecords[teamName] = tr;
}
// 读入并分析比赛记录
int numGames;
cin >> numGames;
cin.ignore();
while (numGames--) {
string line;
getline(cin, line);
splitTeamGoals(line, teamRecords);
}
vector<TeamRecord*> sortedTeamRecords;
map<string, TeamRecord*>::iterator it;
for (it = teamRecords.begin(); it != teamRecords.end(); ++it) {
TeamRecord* tr = it->second;
sortedTeamRecords.push_back(tr);
}
// 使用自定义函数进行排序
sort(sortedTeamRecords.begin(), sortedTeamRecords.end(),
greaterRank);
int ordTeam = 0;
vector<TeamRecord*>::iterator it1;
for (it1 = sortedTeamRecords.begin();
it1 != sortedTeamRecords.end(); ++it1) {
cout << ++ordTeam << ") " << **it1 << endl;
delete (*it1); // 输出后就可以释放空间了
}
if (numTournament > 0) // 最后不能再输出 回车,否则 WA
cout << endl;
}
return 0;
}
环境: C++ 4.5.3 - GNU C++ Compiler with options: -lm -lcrypt -O2 -pipe -DONLINE_JUDGE