PAT甲級題分類彙編——排序

本文爲PAT甲級分類彙編系列文章。html

 

排序題,就是以排序算法爲主的題。純排序,用 std::sort 就能解決的那種,20分都算不上,只能放在乙級,甲級的排序題要麼是排序的規則複雜,要麼是排完序還要作點什麼的。ios

在1051至1100中有6道:算法

題號 標題 分數 大意 時間
1055 The World's Richest 25 限定範圍排序結果 500ms
1056 Mice and Rice 25 分組排序 200ms
1062 Talent and Virtue 25 必定規則的排序 400ms
1075 PAT Judge 25 複雜排序 200ms
1080 Graduate Admission 30 志願與錄取 250ms
1083 List Grades 25 限定範圍排序結果 400ms

選了105六、1075和1080 3道作,其餘不作是由於以爲太水了。app

 

1056:測試

題目要求模擬晉級賽,每組選手中的最高分進入下一組,同一輪中淘汰的名次相同。spa

邊界狀況是隻剩一我的,這時比賽就結束了,是循環的結束條件,因此也不算邊界的坑了。code

主循環中用到兩個 std::vector<int> 對象,分別做爲當前一輪的選手與晉級的選手,在循環的最後一個賦值一個清空。很是巧的是(也多是必然),輸入數據中的順序恰好能夠表示當前一輪。htm

很簡單的題,一遍就AC了。對象

 1 #include <iostream>
 2 #include <vector>
 3 #include <algorithm>
 4 
 5 struct Programmer
 6 {
 7     int index;
 8     int mice;
 9     int score;
10     int rank;
11 };
12 
13 
14 int main(int argc, char const *argv[])
15 {
16     int total, per;
17     std::cin >> total >> per;
18     std::vector<Programmer> prog(total);
19     for (int i = 0; i != total; ++i)
20         prog[i].index = i, std::cin >> prog[i].mice;
21     std::vector<int> current(total);
22     for (int i = 0; i != total; ++i)
23         std::cin >> current[i];
24     
25     std::vector<int> next;
26     while (1)
27     {
28         auto iter = current.begin();
29         int index;
30         while (iter != current.end())
31         {
32             int max = -1;
33             for (int i = 0; i != per && iter != current.end(); ++i, ++iter)
34                 if (prog[*iter].mice > max)
35                 {
36                     index = *iter;
37                     max = prog[*iter].mice;
38                 }
39             ++prog[index].score;
40             next.push_back(index);
41         }
42         if (next.size() == 1)
43             break;
44         current = next;
45         next.clear();
46     }
47 
48     std::sort(prog.begin(), prog.end(), [](const Programmer& lhs, const Programmer& rhs) {
49         return lhs.score > rhs.score;
50     });
51     int count = 2;
52     prog.front().rank = 1;
53     for (auto iter = prog.begin() + 1; iter != prog.end(); ++iter, ++count)
54         if (iter->score == (iter - 1)->score)
55             iter->rank = (iter - 1)->rank;
56         else
57             iter->rank = count;
58     std::sort(prog.begin(), prog.end(), [](const Programmer& lhs, const Programmer& rhs) {
59         return lhs.index < rhs.index;
60     });
61     auto end = prog.end() - 1;
62     for (auto iter = prog.begin(); iter != end; ++iter)
63         std::cout << iter->rank << ' ';
64     std::cout << end->rank << std::endl;
65 
66     return 0;
67 }

 

1075:blog

這道題要求模擬PAT評分系統,統計一系列提交,最後按照用戶來輸出。麻煩的是沒有提交、編譯錯誤、滿分等狀況,以前看到這道題的時候就以爲太煩跳了。

要排好序,主要要搞清楚題目裏的這些概念:總分、滿分題數、有效用戶,還有提交與輸出分數的關係。

一個個來說吧。總分就是全部分數加起來,這很簡單。然而,因爲-1表示編譯錯誤的存在,累加不能直接相加,要判斷是否大於0(大於等於也同樣)。同時還須要一種表示沒有提交過的方法,我就用-2了。

滿分題數,就是把一我的的各題分數一個個和滿分比較,全部相等的數量。這是排序中的第二關鍵字。

有效用戶,就是有過編譯經過的提交的用戶。就算提交完是0分,也算有效用戶,這個點坑到了。

提交與分數,坑在若是提交編譯錯誤,這道題是算0分而不是算沒提交,這個也坑到了。

區區一道25分題就放那麼多坑,我下午放學開始寫,晚上熄燈後才寫完(雖然沒有一直在寫,至少加起來也一個多小時了,但主要是不AC我難受啊),姥姥你心不痛嗎?

  1 #include <iostream>
  2 #include <iomanip>
  3 #include <vector>
  4 #include <algorithm>
  5 
  6 int num_problem;
  7 std::vector<int> problem_full;
  8 
  9 class User
 10 {
 11 public:
 12     User(int _id)
 13         : id_(_id), problems(num_problem, -2)
 14     {
 15         ;
 16     }
 17     void submission(int _pro, int _score)
 18     {
 19         if (_score > problems[_pro])
 20             problems[_pro] = _score;
 21     }
 22     bool operator<(const User& _user) const
 23     {
 24         calculate();
 25         _user.calculate();
 26         if (score_ > _user.score_)
 27             return true;
 28         if (score_ < _user.score_)
 29             return false;
 30         if (perfect_ > _user.perfect_)
 31             return true;
 32         if (perfect_ < _user.perfect_)
 33             return false;
 34         return id_ < _user.id_;
 35     }
 36     bool valid() const
 37     {
 38         calculate();
 39         return valid_;
 40     }
 41     void rank(int _rank)
 42     {
 43         rank_ = _rank;
 44     }
 45     int rank() const
 46     {
 47         return rank_;
 48     }
 49     int score() const
 50     {
 51         calculate();
 52         return score_;
 53     }
 54     friend std::ostream& operator<<(std::ostream& _os, const User& _user);
 55 private:
 56     int id_;
 57     std::vector<int> problems;
 58     mutable bool calculated_;
 59     mutable int score_;
 60     mutable int perfect_;
 61     mutable bool valid_;
 62     int rank_;
 63     void calculate() const
 64     {
 65         if (!calculated_)
 66         {
 67             calculated_ = true;
 68             for (int i = 0; i != problems.size(); ++i)
 69                 if (problems[i] >= 0)
 70                 {
 71                     score_ += problems[i];
 72                     if (problems[i] == problem_full[i])
 73                         ++perfect_;
 74                     valid_ = true;
 75                 }
 76         }
 77     }
 78 };
 79 
 80 std::ostream& operator<<(std::ostream& _os, const User& _user)
 81 {
 82     std::cout << std::setfill('0');
 83     _os << _user.rank_ << ' ';
 84     _os << std::setw(5) << _user.id_ << ' ';
 85     _os << _user.score_;
 86     for (int s : _user.problems)
 87     {
 88         std::cout << ' ';
 89         if (s >= 0)
 90             std::cout << s;
 91         else if (s == -1)
 92             std::cout << '0';
 93         else
 94             std::cout << '-';
 95     }
 96     return _os;
 97 }
 98 
 99 int main(int argc, char const *argv[])
100 {
101     int num_user;
102     int num_submission;
103     std::cin >> num_user >> num_problem >> num_submission;
104 
105     std::vector<User> users;
106     users.reserve(num_user);
107     for (int i = 0; i != num_user; ++i)
108     {
109         users.emplace_back(i + 1);
110     }
111     problem_full.reserve(num_problem);
112     for (int i = 0; i != num_problem; ++i)
113     {
114         int t;
115         std::cin >> t;
116         problem_full.push_back(t);
117     }
118     for (int i = 0; i != num_submission; ++i)
119     {
120         int user, pro, score;
121         std::cin >> user >> pro >> score;
122         --user;
123         --pro;
124         users[user].submission(pro, score);
125     }
126     std::sort(users.begin(), users.end());
127     int count = 1;
128     users.front().rank(count++);
129     for (auto iter = users.begin() + 1; iter != users.end(); ++iter, ++count)
130     {
131         if (iter->score() == (iter - 1)->score())
132             iter->rank((iter - 1)->rank());
133         else
134             iter->rank(count);
135     }
136     for (const auto& u : users)
137         if (u.valid())
138             std::cout << u << std::endl;
139         else
140             break;
141 
142     return 0;
143 }

爲了優雅,我把代碼寫得很OO(實際上是object-based)。雖然也沒有人會去複用它。

還有一點,測試數據裏的case 4很詭異,我提交了3次,時間分別是19一、1十、194ms。更關鍵的是這道題限制就200ms,我要是再寫爛一點不就超時了嗎?還一會超時一會不超時的,搞不懂。

 

1080:

這道題要求模擬志願錄取,核心算法在於分配而不是排序,以前讀題的時候沒注意,給分到這裏來了。

輸入、排序、輸出都很簡單,難在分配,即所謂錄取過程。要是沒有並列的都要錄取這條規則,對排序完的學生遍歷一遍就能夠了,但它偏要有這條,不過誰讓它是30分題呢。講真,我感受這道30分比上一道25分簡單,一遍AC。

我解決並列問題的方法是這樣的:一對iterator,分別指向並列一段的起始和尾後,而後將學校名額「鎖住」,保持它是否有空餘名額的狀態,這時往裏塞。就算超名額也無論,是題目要求的。「鎖住」之後也不用「解鎖」,下次「鎖住」的時候會更新狀態(也許應該換個名字,畢竟lock之後不unlock怪怪的)。

 1 #include <iostream>
 2 #include <vector>
 3 #include <algorithm>
 4 #include <functional>
 5 #include <utility>
 6 using std::rel_ops::operator>;
 7 
 8 struct School
 9 {
10     int quota;
11     std::vector<int> admitted;
12     bool free()
13     {
14         return free_;
15     }
16     void lock()
17     {
18         free_ = admitted.size() < quota;
19     }
20 private:
21     bool free_;
22 };
23 
24 struct Student
25 {
26     int id;
27     int grade_e;
28     int grade_i;
29     std::vector<int> choices;
30     int rank;
31     bool operator<(const Student& _rhs) const
32     {
33         if (grade_e + grade_i < _rhs.grade_e + _rhs.grade_i)
34             return true;
35         if (grade_e + grade_i > _rhs.grade_e + _rhs.grade_i)
36             return false;
37         return grade_e < _rhs.grade_e;
38     }
39     bool operator==(const Student& _rhs) const
40     {
41         return grade_e == _rhs.grade_e && grade_i == _rhs.grade_i;
42     }
43 };
44 
45 int main()
46 {
47     int num_applicant, num_school, num_choice;
48     std::cin >> num_applicant >> num_school >> num_choice;
49     std::vector<School> schools(num_school);
50     std::vector<Student> students(num_applicant);
51     for (auto& s : schools)
52         std::cin >> s.quota;
53     for (int i = 0; i != num_applicant; ++i)
54     {
55         auto& s = students[i];
56         s.id = i;
57         std::cin >> s.grade_e >> s.grade_i;
58         s.choices.resize(num_choice);
59         for (auto& i : s.choices)
60             std::cin >> i;
61     }
62     std::sort(students.begin(), students.end(), std::greater<Student>());
63     for (auto iter = students.begin() + 1; iter != students.end(); ++iter)
64         if (*iter == *(iter - 1))
65             iter->rank = (iter - 1)->rank;
66         else
67             iter->rank = (iter - 1)->rank + 1;
68     auto end = students.begin();
69     while (end != students.end())
70     {
71         auto iter = end;
72         while (end != students.end() && *end == *iter)
73             ++end;
74         for (auto& s : schools)
75             s.lock();
76         for (; iter != end; ++iter)
77         {
78             for (const auto& s : iter->choices)
79                 if (schools[s].free())
80                 {
81                     schools[s].admitted.push_back(iter->id);
82                     break;
83                 }
84         }
85     }
86     for (auto& s : schools)
87     {
88         std::sort(s.admitted.begin(), s.admitted.end());
89         if (!s.admitted.empty())
90         {
91             auto end = s.admitted.end() - 1;
92             for (auto iter = s.admitted.begin(); iter != end; ++iter)
93                 std::cout << *iter << ' ';
94             std::cout << *end;
95         }
96         std::cout << std::endl;
97     }
98 }

本身用 operator< 來實現 operator> 太煩了,我選擇 std::rel_ops 。 

 

還有一個星期就要考了,我10篇才寫了3篇,能夠不用睡覺了。

相關文章
相關標籤/搜索