数据结构(陈越)PAT练习题 第八周:排序(下)

来源:互联网 发布:网络渗透技术教程视频 编辑:程序博客网 时间:2024/05/16 08:46

08-1. Talent and Virtue

时间限制
200 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
CHEN, Li

About 900 years ago, a Chinese philosopher Sima Guang wrote a history book in which he talked about people's talent and virtue. According to his theory, a man being outstanding in both talent and virtue must be a "sage(圣人)"; being less excellent but with one's virtue outweighs talent can be called a "nobleman(君子)"; being good in neither is a "fool man(愚人)"; yet a fool man is better than a "small man(小人)" who prefers talent than virtue.

Now given the grades of talent and virtue of a group of people, you are supposed to rank them according to Sima Guang's theory.

Input Specification:

Each input file contains one test case. Each case first gives 3 positive integers in a line: N (<=105), the total number of people to be ranked; L (>=60), the lower bound of the qualified grades -- that is, only the ones whose grades of talent and virtue are both not below this line will be ranked; and H (<100), the higher line of qualification -- that is, those with both grades not below this line are considered as the "sages", and will be ranked in non-increasing order according to their total grades. Those with talent grades below H but virtue grades not are cosidered as the "noblemen", and are also ranked in non-increasing order according to their total grades, but they are listed after the "sages". Those with both grades below H, but with virtue not lower than talent are considered as the "fool men". They are ranked in the same way but after the "noblemen". The rest of people whose grades both pass the L line are ranked after the "fool men".

Then N lines follow, each gives the information of a person in the format:

ID_Number Virtue_Grade Talent_Grade
where ID_Number is an 8-digit number, and both grades are integers in [0, 100]. All the numbers are separated by a space.

Output Specification:

The first line of output must give M (<=N), the total number of people that are actually ranked. Then M lines follow, each gives the information of a person in the same format as the input, according to the ranking rules. If there is a tie of the total grade, they must be ranked with respect to their virtue grades in non-increasing order. If there is still a tie, then output in increasing order of their ID's.

Sample Input:
14 60 8010000001 64 9010000002 90 6010000011 85 8010000003 85 8010000004 80 8510000005 82 7710000006 83 7610000007 90 7810000008 75 7910000009 59 9010000010 88 4510000012 80 10010000013 90 9910000014 66 60
Sample Output:
1210000013 90 9910000012 80 10010000003 85 8010000011 85 8010000004 80 8510000007 90 7810000006 83 7610000005 82 7710000002 90 6010000014 66 6010000008 75 7910000001 64 90

这一题前面的导言有点误导人。我在这里说明下题目的要求。题目里给出了两个分数L和H,只有 virtue 和 talent 分数都不低于L的才会进入排名中。两个分数都不低于H的是 sages ;之后是 noblemen ,他们的 virtue 分数达到了H,但是 talent 分数低于H;再后面的是 fool men,他们的两个分数都低于H,并且 virtue 分数不低于 talent 分数;剩下的人排在最后,他们当中包括两个分数都没到H,并且 talent 分数高于 virtue 的人,以及 talent 分数达到H,但 virtue 分数低于H的人。在这四组成绩中,每个组内部按照总分从高到低的顺序排列;如果总分一样,就把 virtue 分高的排前面;如果 virtue 分也一样,说明他们的 talent 分也一样,这时就按他们的ID号从低到高排列。

把这些关系搞清楚了,就可以排序了。这一题很明显非常适合用桶排序。我的方法是,建立 sage, noble, fool, small 四个桶,这里我就用 small 表示最后一组的人了。在读入数据时,先把所有人按情况放入某个桶内,然后再对每个桶分别进行排序。我用了 vector 模版来表示桶,然后调用STL里的 sort 函数进行排序,这里我重载了 < 运算符。为了防止会超时,我把 cin 和 cout 的输入输出方式换成了 scanf 和 printf 。如果做一下测试,会发现 cin 和 cout 真的会比 scanf 和 printf 慢很多。下面是完整的代码:

#include <iostream>#include "stdio.h"#include <vector>#include <algorithm>using namespace std;int N, L, H;int Msage=0, Mnoble=0, Mfool=0, Msmall=0;struct student{int id;int virtue;int talent;int total;};bool operator < (const student &stu1, const student &stu2){if (stu1.total>stu2.total)return true;else if (stu1.total==stu2.total)if (stu1.virtue>stu2.virtue)return true;else if (stu1.virtue==stu2.virtue)if (stu1.id<stu2.id)return true;return false;}int main(){cin >> N >> L >> H;vector<student> sage, noble, fool, small;for (int i=0; i<N; ++i){student tmp;scanf("%d %d %d", &tmp.id, &tmp.virtue, &tmp.talent);tmp.total = tmp.virtue + tmp.talent;if (tmp.virtue<L || tmp.talent<L)continue;if (tmp.virtue>=H && tmp.talent>=H){sage.push_back( tmp );++Msage;}else if (tmp.talent>=L && tmp.virtue>=H){noble.push_back( tmp );++Mnoble;}else if (tmp.talent<H && tmp.virtue<H && tmp.virtue>=tmp.talent){fool.push_back( tmp );++Mfool;}else{small.push_back( tmp );++Msmall;}}sort( sage.begin(), sage.end() );sort( noble.begin(), noble.end() );sort( fool.begin(), fool.end() );sort( small.begin(), small.end() );cout << Msage+Mnoble+Mfool+Msmall;for (int i=0; i<Msage; ++i)printf("\n%d %d %d", sage[i].id, sage[i].virtue, sage[i].talent);for (int i=0; i<Mnoble; ++i)printf("\n%d %d %d", noble[i].id, noble[i].virtue, noble[i].talent);for (int i=0; i<Mfool; ++i)printf("\n%d %d %d", fool[i].id, fool[i].virtue, fool[i].talent);for (int i=0; i<Msmall; ++i)printf("\n%d %d %d", small[i].id, small[i].virtue, small[i].talent);return 0;}


08-2. The World's Richest

时间限制
400 ms
内存限制
128000 kB
代码长度限制
8000 B
判题程序
Standard
作者
CHEN, Yue

Forbes magazine publishes every year its list of billionaires based on the annual ranking of the world's wealthiest people. Now you are supposed to simulate this job, but concentrate only on the people in a certain range of ages. That is, given the net worths of N people, you must find the M richest people in a given range of their ages.

Input Specification:

Each input file contains one test case. For each case, the first line contains 2 positive integers: N (<=105) - the total number of people, and K (<=103) - the number of queries. Then N lines follow, each contains the name (string of no more than 8 characters without space), age (integer in (0, 200]), and the net worth (integer in [-106, 106]) of a person. Finally there are K lines of queries, each contains three positive integers: M (<= 100) - the maximum number of outputs, and [Amin, Amax] which are the range of ages. All the numbers in a line are separated by a space.

Output Specification:

For each query, first print in a line "Case #X:" where X is the query number starting from 1. Then output the M richest people with their ages in the range [Amin, Amax]. Each person's information occupies a line, in the format

Name Age Net_Worth
The outputs must be in non-increasing order of the net worths. In case there are equal worths, it must be in non-decreasing order of the ages. If both worths and ages are the same, then the output must be in non-decreasing alphabetical order of the names. It is guaranteed that there is no two persons share all the same of the three pieces of information. In case no one is found, output "None".

Sample Input:
12 4Zoe_Bill 35 2333Bob_Volk 24 5888Anny_Cin 95 999999Williams 30 -22Cindy 76 76000Alice 18 88888Joe_Mike 32 3222Michael 5 300000Rosemary 40 5888Dobby 24 5888Billy 24 5888Nobody 5 04 15 454 30 354 5 951 45 50
Sample Output:
Case #1:Alice 18 88888Billy 24 5888Bob_Volk 24 5888Dobby 24 5888Case #2:Joe_Mike 32 3222Zoe_Bill 35 2333Williams 30 -22Case #3:Anny_Cin 95 999999Michael 5 300000Alice 18 88888Cindy 76 76000Case #4:None

这一题乍看之下还是桶排序,但实际上并没有那个简单。桶是什么?可以按照年龄来分桶,最后输出时,其实又是一个归并排序。这样操作其实还是比较麻烦。也可以在题目要求的年龄范围内排序,并且只排出前几名的就可以了。这两种方法都得自己写出排序算法。而我用的方法非常简单,先给所有的人一次性排好序,然后从前到后给出年龄范围内的人。至于排序算法,依然是调用STL中的 sort 函数,并且重载 < 运算符。STL里只会用到 < 符号。下面是程序代码:

#include <iostream>#include "stdio.h"#include <vector>#include <algorithm>#include <string>using std::string;using std::cin;using std::cout;using std::endl;int N, K;bool none;struct people{string name;int age;int worth;};bool operator < (const people &p1, const people &p2){if (p1.worth>p2.worth)return true;else if (p1.worth==p2.worth)if (p1.age<p2.age)return true;else if (p1.age==p2.age)if (p1.name<p2.name)return true;return false;}int main(){cin >> N >> K;people a[N];for (int i=0; i<N; ++i){cin >> a[i].name >> a[i].age >> a[i].worth;}std::sort( a, a+N );int num, la, sa, count;for (int quire=1; quire<=K; ++quire){count = 0;cin >> num >> la >> sa;printf("Case #%d:\n", quire);for (int i=0; i<N; ++i){if (a[i].age>=la && a[i].age<=sa){cout << a[i].name << ' ' << a[i].age << ' ' << a[i].worth << endl;++count;}if (count==num)break;}if (count==0)cout << "None\n";}return 0;}


08-3. Sort with Swap(0,*)

时间限制
150 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
CHEN, Yue

Given any permutation of the numbers {0, 1, 2,..., N-1}, it is easy to sort them in increasing order. But what if Swap(0, *) is the ONLY operation that is allowed to use? For example, to sort {4, 0, 2, 1, 3} we may apply the swap operations in the following way:

Swap(0, 1) => {4, 1, 2, 0, 3}
Swap(0, 3) => {4, 1, 2, 3, 0}
Swap(0, 4) => {0, 1, 2, 3, 4}

Now you are asked to find the minimum number of swaps need to sort the given permutation of the first N nonnegative integers.

Input Specification:

Each input file contains one test case, which gives a positive N (<=105) followed by a permutation sequence of {0, 1, ..., N-1}. All the numbers in a line are separated by a space.

Output Specification:

For each case, simply print in a line the minimum number of swaps need to sort the given permutation.

Sample Input:
10 3 5 7 2 6 4 9 0 8 1
Sample Output:
9

输入的第一个数表示数据个数,并不是序列里的数。关于这一题姥姥给出了分析,可以数一数有多少个单元环和多元环,然后直接通过公式计算出来。不过像我们这样的小白,肯定想不出这样高大上的方法,所以还是实际来交换看看到底需要多少步。实际交换时有这样一个问题,比如我要交换0和7,那么我必须要在数组里找到0和7。如果每次都把数组遍历一遍,显然会耽误时间。姥姥的做法是再开一个数组为门作为索引,只是这样做会多消耗一些内存。我的做法是,把数组的下标和元素值反过来表示。例如 a[1]=3,它并不是表示第1个元素是3,而是第3个元素的值为1,或者说值为1的元素在第3个位置。这样一来,当我要找元素k时,通过a[k]就可以知道它的下标是多少。当然交换某两个数组元素时,其实就是交换原始数据里那两个数的下标,与原始的交换两个数的效果一样。在交换时,由于每次只用0来交换,所以当某个环里不含0时,就必须先把0交换进去。在某个环内交换时,并不需要真的每次都拿0来交换,只需要像表排序那样把每个元素挪到正确位置就可以了。下面是完整的代码:

#include <iostream>using namespace std;int main(){int N, k, tmp;int* a;cin >> N;a = new int [N];for (int i=0; i<N; ++i){cin >> k;a[k] = i;}int num = 0;for (int i=0; i<N; ++i){if (a[i]==i)continue;if (i!=0){swap( a[0], a[i] );++num;}int j = 0;while (a[j]!=j){tmp = a[j];a[j] = j;j = tmp;++num;}--num;}cout << num;delete [] a;return 0;}

0 0
原创粉丝点击