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篇,能够不用睡觉了。

相关文章
相关标签/搜索