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

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 80
10000001 64 90
10000002 90 60
10000011 85 80
10000003 85 80
10000004 80 85
10000005 82 77
10000006 83 76
10000007 90 78
10000008 75 79
10000009 59 90
10000010 88 45
10000012 80 100
10000013 90 99
10000014 66 60
Sample Output:
12
10000013 90 99
10000012 80 100
10000003 85 80
10000011 85 80
10000004 80 85
10000007 90 78
10000006 83 76
10000005 82 77
10000002 90 60
10000014 66 60
10000008 75 79
10000001 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 4
Zoe_Bill 35 2333
Bob_Volk 24 5888
Anny_Cin 95 999999
Williams 30 -22
Cindy 76 76000
Alice 18 88888
Joe_Mike 32 3222
Michael 5 300000
Rosemary 40 5888
Dobby 24 5888
Billy 24 5888
Nobody 5 0
4 15 45
4 30 35
4 5 95
1 45 50
Sample Output:
Case #1:
Alice 18 88888
Billy 24 5888
Bob_Volk 24 5888
Dobby 24 5888
Case #2:
Joe_Mike 32 3222
Zoe_Bill 35 2333
Williams 30 -22
Case #3:
Anny_Cin 95 999999
Michael 5 300000
Alice 18 88888
Cindy 76 76000
Case #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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用,数据结构PAT练习题中包含了关于树的题目。其中有一道题目将二叉树看作图,并对它作图的深度优先遍历,与原二叉树的结果是相同的。答案选项包括前序遍历、中序遍历、后序遍历和层次序遍历。 根据引用和引用,数据结构PAT练习题还包含了测试各种排序算法的题目。这些题目旨在测试不同排序算法在不同数据情况下的表现。测试数据包括只有1个元素、11个不相同的整数、随机整数、顺序整数、逆序整数、基本有序的整数和随机正整数等。 综上所述,数据结构PAT练习题涉及到树的遍历和排序算法的应用。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [数据结构习题-Dijkstra](https://download.csdn.net/download/li_guizhen/2853501)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [数据结构陈越PAT练习题 第七排序(上)](https://blog.csdn.net/ustcfdm/article/details/43671249)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值