10194 - Football (aka Soccer)

题意:
读入各个球队的名字, 和球队之间比赛的进球数, 要求统计各个球队的比赛总场数, 总得分等信息, 按以下优先级顺序进行输出:
1. 最高得分
2. 最多胜利场次
3. 最多净胜球数(进球-失球)
4. 最多进球数
5. 最少比赛场数
6. 球队名字典序, 小的排前面(比较时不区分大小写)   
注意: scored 3 goals 指的是进球数为 3, 不是得分 3; 看题目的时候这个理解错了, 纠结了好久, 无从下手.

思路:
1. 读入一行, 按 # 拆分出球队名和进球数.
2. 计算得分, 净胜球等信息.
3. 根据重载的 > 进行排序, 比较规则如题意所示.
4. 按顺序进行输出.

要点:
1. 重载 > 可以是成员函数, 重载 << 时必须是友元函数, 因为其要接收一个 ostream& 的参数. ???
2. 对于 if, for, 如果想不写{}, 那么其一行写完的句子必须简短到可以直接补在 if, for 后面, 形成一行. 

题目:
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=98&page=show_problem&problem=1135

代码:

# 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

你可能感兴趣的:(uva,Football,(aka,Soccer),10194)