PAT 第三周(1011-1014)

是沉迷奥运的一周,目前中国队三金,真的大爱武大靖,加油!

话不多说,这周的四道题,主要是后两题卡测试点,不至于做不出来。

目录

1011 World Cup Betting

1012 The Best Rank

1013 Battle Over Cities

1014 Waiting in Line


 1011 World Cup Betting

With the 2010 FIFA World Cup running, football fans the world over were becoming increasingly excited as the best players from the best teams doing battles for the World Cup trophy in South Africa. Similarly, football betting fans were putting their money where their mouths were, by laying all manner of World Cup bets.

Chinese Football Lottery provided a "Triple Winning" game. The rule of winning was simple: first select any three of the games. Then for each selected game, bet on one of the three possible results -- namely W for win, T for tie, and L for lose. There was an odd assigned to each result. The winner's odd would be the product of the three odds times 65%.

For example, 3 games' odds are given as the following:

 W    T    L
1.1  2.5  1.7
1.2  3.1  1.6
4.1  1.2  1.1

To obtain the maximum profit, one must buy W for the 3rd game,T for the 2nd game, and T for the 1st game. If each bet takes 2 yuans, then the maximum profit would be (4.1×3.1×2.5×65%−1)×2=39.31 yuans (accurate up to 2 decimal places).

Input Specification:

Each input file contains one test case. Each case contains the betting information of 3 games. Each game occupies a line with three distinct odds corresponding to W, T and L.

Output Specification:

For each test case, print in one line the best bet of each game, and the maximum profit accurate up to 2 decimal places. The characters and the number must be separated by one space.

Sample Input:

1.1 2.5 1.7
1.2 3.1 1.6
4.1 1.2 1.1

Sample Output:

T T W 39.31

送分题,不过多解释。

【本题代码】

#include<iostream>
#include<iomanip>
#include<cmath>
using namespace std;
int main()
{
	float w, t, l;
	float best[3];
	char bet[3];
	for (int i = 0; i < 3; i++) {
		cin >> w >> t >> l;
		float temp = max(w, t);
		best[i]=max(temp, l);
		if (best[i] == w)bet[i] = 'W';
		if (best[i] == t)bet[i] = 'T';
		if (best[i] == l)bet[i] = 'L';
	}
	for (int i = 0; i < 3; i++) cout << bet[i] << " ";
	cout << fixed << setprecision(2) << (best[2] * best[1] * best[0] * 0.65 - 1) * 2;
	return 0;
}

1012 The Best Rank

To evaluate the performance of our first year CS majored students, we consider their grades of three courses only: C - C Programming Language, M - Mathematics (Calculus or Linear Algrbra), and E - English. At the mean time, we encourage students by emphasizing on their best ranks -- that is, among the four ranks with respect to the three courses and the average grade, we print the best rank for each student.

For example, The grades of C, M, E and A - Average of 4 students are given as the following:

StudentID  C  M  E  A
310101     98 85 88 90
310102     70 95 88 84
310103     82 87 94 88
310104     91 91 91 91

Then the best ranks for all the students are No.1 since the 1st one has done the best in C Programming Language, while the 2nd one in Mathematics, the 3rd one in English, and the last one in average.

Input Specification:

Each input file contains one test case. Each case starts with a line containing 2 numbers N and M (≤2000), which are the total number of students, and the number of students who would check their ranks, respectively. Then N lines follow, each contains a student ID which is a string of 6 digits, followed by the three integer grades (in the range of [0, 100]) of that student in the order of C, M and E. Then there are M lines, each containing a student ID.

Output Specification:

For each of the M students, print in one line the best rank for him/her, and the symbol of the corresponding rank, separated by a space.

The priorities of the ranking methods are ordered as A > C > M > E. Hence if there are two or more ways for a student to obtain the same best rank, output the one with the highest priority.

If a student is not on the grading list, simply output N/A.

Sample Input:

5 6
310101 98 85 88
310102 70 95 88
310103 82 87 94
310104 91 91 91
310105 85 90 90
310101
310102
310103
310104
310105
999999

Sample Output:

1 C
1 M
1 E
1 A
3 A
N/A

首先,本题实质是一道排序题。我采用了冒泡排序。

其次,有几点需要注意的:

①测试点2为多人成绩相同时,排名也要相同,例如:1 1 3 4 5 这样的排名,而不是 1 2 3 4 5 或者 1 1 2 3 4,

②这道排序题还需保留学生ID与其成绩排名的对应关系,所以要格外注意在排序算法中保留排名的步骤要先于算法中的交换swap步骤,这是我一开始并未注意到的错误点,

③对于其他博主博客中说的平均成绩四舍五入的做法,并未采取,干脆全部已float类型保存,依旧能够AC。

④本题排序并非是取成绩的前三名,切勿审题错误,而是只要有成绩就有排名,这是我一开始做题的犯的第一个低级错误

【本题代码】

#include<iostream>
#include<map>
using namespace std;
void Sort(float*, int, float*, float*, float*);
void swap(float& a, float& b);
int n, m;
string* id;
float* C; map<string, int> rankC;
float* M; map<string, int> rankM;
float* E; map<string, int> rankE;
float* A; map<string, int> rankA;
int main()
{
	cin >> n >> m;
	id = new string[n];
	string* check = new string[m];
	C = new float[n];
	M = new float[n];
	E = new float[n];
	A = new float[n];
	for (int i = 0; i < n; i++) {
		cin >> id[i] >> C[i] >> M[i] >> E[i];
		A[i]= (C[i] + M[i] + E[i])/3;
	}
	for (int i = 0; i < m; i++)
		cin >> check[i];
	Sort(A, 1, C, M, E);
	Sort(C, 2, A, M, E);
	Sort(M, 3, A, C, E);
	Sort(E, 4, A, C, M);

	for (int i = 0; i < m; i++) {
		int bestRank = n + 1;
		string way = "N/A";
		if (rankA.find(check[i]) != rankA.end()) 
			if (rankA.find(check[i])->second < bestRank) {
				bestRank = rankA.find(check[i])->second;
				way = "A";
			}
		if (rankC.find(check[i]) != rankC.end()) 
			if (rankC.find(check[i])->second < bestRank) {
				bestRank = rankC.find(check[i])->second;
				way = "C";
			}
		if (rankM.find(check[i]) != rankM.end())
			if (rankM.find(check[i])->second < bestRank) {
				bestRank = rankM.find(check[i])->second;
				way = "M";
			}
		if (rankE.find(check[i]) != rankE.end())
			if (rankE.find(check[i])->second < bestRank) {
				bestRank = rankE.find(check[i])->second;
				way = "E";
			}
		if (bestRank <= n)cout << bestRank << " ";
		cout << way << endl;
	}
	return 0;
}
void Sort(float* grade, int priority, float* g1, float* g2, float* g3)//冒泡排序
{
	int  key, temp2 = -1;
	float max, temp1 = -1;
	for (int i = 0; i < n; i++)
	{
		max = -1; key = i - 1;
		for (int j = i; j < n; j++)
			if (grade[j] > max) {
				max = grade[j];
				key = j;
			}
		if (priority == 1)
			if (max == temp1)//测试点2 多人成绩相同时
				rankA.insert(pair<string, int>(id[key], temp2));
			else {
				rankA.insert(pair<string, int>(id[key], (i + 1)));
				temp2 = i + 1;
			}
		if (priority == 2)
			if (max == temp1)//测试点2 多人成绩相同时
				rankC.insert(pair<string, int>(id[key], temp2));
			else {
				rankC.insert(pair<string, int>(id[key], (i + 1))); 
				temp2 = i + 1;
			}
		if (priority == 3)
			if (max == temp1)
				rankM.insert(pair<string, int>(id[key], temp2));
			else {
				rankM.insert(pair<string, int>(id[key], (i + 1))); 
				temp2 = i + 1;
			}
		if (priority == 4)
			if (max == temp1)
				rankE.insert(pair<string, int>(id[key], temp2));
			else {
				rankE.insert(pair<string, int>(id[key], (i + 1))); 
				temp2 = i + 1;
			}
		//cout << key << " " << id[key] << " " << max << endl;
		temp1 = max;//上一个最大数
		swap(grade[i], grade[key]);
		swap(g1[i], g1[key]);
		swap(g2[i], g2[key]);
		swap(g3[i], g3[key]);
		swap(id[i], id[key]);
	}
}
void swap(float& a, float& b)
{
	float temp = a;
	a = b;
	b = temp;
}

1013 Battle Over Cities

It is vitally important to have all the cities connected by highways in a war. If a city is occupied by the enemy, all the highways from/toward that city are closed. We must know immediately if we need to repair any other highways to keep the rest of the cities connected. Given the map of cities which have all the remaining highways marked, you are supposed to tell the number of highways need to be repaired, quickly.

For example, if we have 3 cities and 2 highways connecting city1​-city2​ and city1​-city3​. Then if city1​ is occupied by the enemy, we must have 1 highway repaired, that is the highway city2​-city3

Input Specification:

Each input file contains one test case. Each case starts with a line containing 3 numbers N (<1000), M and K, which are the total number of cities, the number of remaining highways, and the number of cities to be checked, respectively. Then M lines follow, each describes a highway by 2 integers, which are the numbers of the cities the highway connects. The cities are numbered from 1 to N. Finally there is a line containing K numbers, which represent the cities we concern.

Output Specification:

For each of the K cities, output in a line the number of highways need to be repaired if that city is lost.

Sample Input:

3 2 3
1 2
1 3
1 2 3

Sample Output:

1
0
0

本题的实质即为求去除某一顶点后图的连通分量个数。

感觉自己审题也没有什么大问题,就是采用的不是常规的求连通分量个数的DFS方法,目前就是测试点1过不了,我也傲娇不想改成DFS方法。先放上的是17分的代码对比AC的代码如下,如果有好人能看出我之前代码(Connect函数)的bug就好了,没有的话待小禾之后看出来错误再修改博客啦。有人可能问为啥不AC1013完再写本周的博客,主要是小禾刚刚总算把1014AC掉,想着趁着脑袋里想法多赶紧把这题解析掉,呜。


好啦,小禾回来修改了。现在是吃完饱饱的晚上总算看出bug,这周博客不会等到明天再修改了。

原先17分的代码主要是没有考虑这样一种情况,

5 4 1
1 3
1 4
2 3
4 5
5

对于上面测试用例的输出,会输出1,其实简单画个图会发现其实是0,问题出现在哪呢?

就是我代码现在添上去的标注注释“重要”二字的那三行,原先出现的问题便是一开始划分在一个连通域中的三点1 3 4,在遍历点2相邻顶点后导致点3的连通域序号发生变化,但此时并没有相应的改变和点3处于同一连通域的其他点的序号,从而误以为有两个连通域存在,因此加上注释的那三行,遍历和点2在同一连通域的其他点相应地改变序号才是正确算法,但是如此三层循环却又带来超时的缘故。

综上,还是多刷刷题,遇到这种具有传统DFS解法的考场不要像我一样另辟蹊径,以为同样是胜利的彼岸,其实不然,要是我熟练到看到连通域问题本质便知道传统方法是DFS,便不会出错了。

当然解决连通域问题还有一个并查集的方法,小禾没有掌握,假期又不是特别想学,想要了解的同学可以再去其他博主那边看看。

【本题代码】

// 17分->添上注释“重要”的那部分测试点1过了,最后一个测试点超时(21分)
#include<iostream>
using namespace std;
int Connect(int, int**);
int n, m, k, a, b, c;
int main()
{
	cin >> n >> m >> k;
	int** edge = new int* [n];
	for (int i = 0; i < n; i++)
	{
		edge[i] = new int[n];
		for (int j = 0; j < n; j++)
			edge[i][j] = 0;
	}
	for (int i = 0; i < m; i++) {
		cin >> a >> b;
		edge[a - 1][b - 1] = 1;
		edge[b - 1][a - 1] = 1;
	}
	for (int i = 0; i < k; i++)
	{
		cin >> c;
		cout << Connect(c-1, edge)<<endl;
	}
	return 0;
}
int Connect(int city, int** edge)
{
	int* Mark = new int[n];
	bool* flag = new bool[n];
	for (int i = 0; i < n; i++)
	{
		Mark[i] = i; 
		flag[i] = false;
	}
	for (int i = 0; i < n; i++)
		if (i != city) {
			for (int j = i + 1; j < n; j++)
				if (edge[i][j] == 1 && j != city) {
                    for (int t = 0; t < n; t++)/重要
						if (Mark[t] == Mark[j])
							Mark[t] = Mark[i];
					Mark[j] = Mark[i];
                }
		}
	for (int i = 0; i < n; i++)
		flag[Mark[i]] = true;
	int t = 0;
	for (int i = 0; i < n; i++)
		if (flag[i] && i != city)
			t++;
	return t - 1;
}
//25分
#include<iostream>
using namespace std;
//int Connect(int, int**);
void DFS(int j, int**);
int n, m, k, a, b, c;
bool* visited;
int main()
{
	cin >> n >> m >> k;//本题本质:图的连通区域个数
	int** edge = new int* [n];
	visited = new bool[n];
	for (int i = 0; i < n; i++)
	{
		visited[i] = false;
		edge[i] = new int[n];
		for (int j = 0; j < n; j++)
			edge[i][j] = 0;
	}
	for (int i = 0; i < m; i++) {
		cin >> a >> b;
		edge[a - 1][b - 1] = 1;
		edge[b - 1][a - 1] = 1;
	}
	for (int i = 0; i < k; i++)
	{
		cin >> c;
		//cout << Connect(c-1, edge) << endl;
		for (int k = 0; k < n; k++)
			visited[k] = false;
		int t = 0;
		visited[c - 1] = true;
		for (int j = 0; j < n; j++)
			if (!visited[j])
			{
				DFS(j, edge);
				t++;
			}
		cout << t-1 << endl;
	}
	return 0;
}
void DFS(int j, int** edge)
{
	visited[j] = true;
	for (int i = 0; i < n; i++)
		if (edge[j][i] && !visited[i])
			DFS(i, edge);
}

1014 Waiting in Line

Suppose a bank has N windows open for service. There is a yellow line in front of the windows which devides the waiting area into two parts. The rules for the customers to wait in line are:

  • The space inside the yellow line in front of each window is enough to contain a line with M customers. Hence when all the N lines are full, all the customers after (and including) the (NM+1)st one will have to wait in a line behind the yellow line.
  • Each customer will choose the shortest line to wait in when crossing the yellow line. If there are two or more lines with the same length, the customer will always choose the window with the smallest number.
  • Customeri​ will take Ti​ minutes to have his/her transaction processed.
  • The first N customers are assumed to be served at 8:00am.

Now given the processing time of each customer, you are supposed to tell the exact time at which a customer has his/her business done.

For example, suppose that a bank has 2 windows and each window may have 2 customers waiting inside the yellow line. There are 5 customers waiting with transactions taking 1, 2, 6, 4 and 3 minutes, respectively. At 08:00 in the morning, customer1​ is served at window1​ while customer2​ is served at window2​. Customer3​ will wait in front of window1​ and customer4​ will wait in front of window2​. Customer5​ will wait behind the yellow line.

At 08:01, customer1​ is done and customer5​ enters the line in front of window1​ since that line seems shorter now. Customer2​ will leave at 08:02, customer4​ at 08:06, customer3​ at 08:07, and finally customer5​ at 08:10.

Input Specification:

Each input file contains one test case. Each case starts with a line containing 4 positive integers: N (≤20, number of windows), M (≤10, the maximum capacity of each line inside the yellow line), K (≤1000, number of customers), and Q (≤1000, number of customer queries).

The next line contains K positive integers, which are the processing time of the K customers.

The last line contains Q positive integers, which represent the customers who are asking about the time they can have their transactions done. The customers are numbered from 1 to K.

Output Specification:

For each of the Q customers, print in one line the time at which his/her transaction is finished, in the format HH:MM where HH is in [08, 17] and MM is in [00, 59]. Note that since the bank is closed everyday after 17:00, for those customers who cannot be served before 17:00, you must output Sorry instead.

Sample Input:

2 2 7 5
1 2 6 4 3 534 2
3 4 5 6 7

Sample Output:

08:07
08:06
08:10
17:00
Sorry

这道1014目前是我本周花时最多的一道,可能还是源于我的代码比较冗长的缘故。

在这里主要说一下测试点4与5的不同,因为我是逐一攻克的。

测试点5:17:00截止指的是开始服务时间而不是结束服务时间,若17:00前已经开始服务,无论时间多久都要服务完。

主要是看题意这边: Note that since the bank is closed everyday after 17:00, for those customers who cannot be served before 17:00, you must output Sorry instead. 这里是cannot be served,是指请求服务要在17:00前,也就是允许17:00后还进行处理。但是不能在17:00后请求处理。

测试点4:若总时间totalTime>=540分钟,还有客户没有排进黄线,则剩下的客户全部都不能进行服务。其实我是有处理这部分的,但是问题出现在由于totalTime>=540分钟,那么此时便不会有顾客排进黄线中,那么刚刚所说的totalTime就没必要加上当前剩余最小服务时间那部分,就需再变回原来值(前一个<540的值),close置1。同时后期针对close已在客户排队期间置1,要有一个特殊处理对应代码注释掉的if(close)部分。注意:注释掉的部分是按照时间流逝处理的每个customer,而实则可以不用那么麻烦,对应注释掉的代码后面的一个for循环块,直接对所有排队的customer计算等到开始服务的时间,若<540便可以计算出服务结束时间(+所需服务时间即可),否则Sorry无法被服务。当然两种方法均可AC,主要是要注意之前进黄线时发生close置1的情况需要将totalTime变回前一个<540的值

针对测试点4,我构造了一个测试用例,供大家选用:

input:

2 2 7 7
540 540 1 1 1 1 1
1 2 3 4 5 6 7

 output:

17:00
17:00
Sorry
Sorry
Sorry
Sorry
Sorry

此外还有一些测试用例,方便大家debug,希望有帮助:

 input:

2 2 7 7
540 1 1 1 1 1 1
1 2 3 4 5 6 7

 output:

17:00
08:01
Sorry
08:02
08:03
08:04
08:05

  input:(有关测试点5)

2 2 7 7
3 3 3 3 533 534 2
1 2 3 4 5 6 7

 output:

08:03
08:03
08:06
08:06
16:59
17:00
17:01

【本题代码】

#include<iostream>
#include<vector>
using namespace std;
int main()
{
	int n, m, k, q, query;
	cin >> n >> m >> k >> q;
	int* window = new int[n];
	int** serve = new int* [n];
	int** wait = new int* [n];
	int* customer = new int[k];
	int* leave = new int[k];
	for (int j = 0; j < n; j++) {
		window[j] = 0;
		wait[j] = new int[m];
		serve[j] = new int[m];
		for (int i = 0; i < m; i++) {
			wait[j][i] = 0;
			serve[j][i] = 0;
		}
	}
	int totalTime = 0;
	int close = 0;
	for (int t = 0; t < k; t++) { // 序号1-K
		leave[t] = -1;
		cin >> customer[t];
		int flag = 0;
		if (!close) {
			int mWindow = m, mWin;
			for (int j = 0; j < n; j++)
				if (window[j] < m && window[j] < mWindow)
				{
					mWindow = window[j];
					mWin = j;
					flag = 1;//不用等待,直接进黄线内
				}
			if (flag) {
				wait[mWin][window[mWin]] = customer[t];//顾客服务时间
				serve[mWin][window[mWin]] = t;//顾客编号
				window[mWin]++;
			}
			else//需等待
			{
				int min = wait[0][0], minW = 0;
				for (int i = 1; i < n; i++) {
					if (wait[i][0] < min) {
						minW = i;
						min = wait[i][0];
					}
				}
				totalTime += min;
				if (totalTime >= 540) {//排不进黄线内
					totalTime -= min;关键4:总时间无需前进 因为此时没有customer排进黄线
					leave[t] = -1;
					close = 1;
				}
				else {
					for (int i = 0; i < n; i++)
					{
						wait[i][0] -= min;
						if (wait[i][0] == 0)
						{
							window[i]--;
							leave[serve[i][0]] = totalTime;
							for (int a = 0; a < m - 1; a++)
							{
								wait[i][a] = wait[i][a + 1];//前移一位
								serve[i][a] = serve[i][a + 1];
							}
							wait[i][m - 1] = 0;
						}
					}
					window[minW]++;
					wait[minW][m - 1] = customer[t];
					serve[minW][m - 1] = t;
				}
			}
		}
		else leave[t] = -1;
	}
	/*
	if(close){//有排不进黄线内的customer
		for (int i = 0; i < n; i++)
			if (window[i]) 
				for (int j = 0; j < m; j++)
					if (wait[i][j] != 0)
						if (j > 0)
							leave[serve[i][j]] = -1;
						else//对于现在窗口正在服务的服务完
							leave[serve[i][j]] = totalTime + wait[i][j];
	}
	else {
		int sum = 0;
		for (int i = 0; i < n; i++)
			sum += window[i];
		while (sum > 0 && (!close)) {
			int min = 0x3f3f3f3f;
			for (int i = 0; i < n; i++) {
				if (window[i] > 0 && wait[i][0] < min)
					min = wait[i][0];
			}
			totalTime += min;
			if (totalTime >= 540) {
				for (int i = 0; i < n; i++)
				{
					if (window[i]) {
						wait[i][0] -= min;
						if (wait[i][0] == 0)//窗口排队队伍不再前移,未开始服务的人sorry
							leave[serve[i][0]] = totalTime;
						for (int j = 0; j < m; j++)
						{
							if (wait[i][j] != 0)
								if (j > 0)
									leave[serve[i][j]] = -1;
								else//对于现在窗口正在服务的服务完
									leave[serve[i][j]] = totalTime + wait[i][j];
						}
					}
				}
				close = 1;//break;
			}
			else {
				for (int i = 0; i < n; i++)
				{
					if (window[i]) {
						wait[i][0] -= min;
						if (wait[i][0] == 0)
						{
							window[i]--;
							leave[serve[i][0]] = totalTime;
							for (int a = 0; a < m - 1; a++)
							{
								wait[i][a] = wait[i][a + 1];//前移一位
								serve[i][a] = serve[i][a + 1];
							}
							wait[i][m - 1] = 0;
						}
					}
				}
				sum = 0;
				for (int i = 0; i < n; i++)
					sum += window[i];
			}
		}
	}*/
	for(int i=0;i< n; i++)
		if (window[i]) {
			int j; int temp = 0;
			for (j = 0; j < m; j++) {
				if (wait[i][j] != 0) {
					temp += wait[i][j];
					leave[serve[i][j]] = totalTime + temp;
					if (leave[serve[i][j]]>=540)break;
				}
			}
			j++;
			while (j < m) {
				if (wait[i][j] != 0)leave[serve[i][j]] = -1;
				j++;
			}
		}
	for (int i = 0; i < q; i++)
	{
		cin >> query;
		if (leave[query - 1] == -1)
			cout << "Sorry" << endl;
		else {
			if (8 + leave[query - 1] / 60 < 10)
				cout << "0";
			cout << 8 + leave[query - 1] / 60;
			cout << ":";
			if (leave[query - 1] % 60 < 10)
				cout << "0";
			cout << leave[query - 1] % 60;
			cout << endl;
		}
	}
	return 0;
}

that's all~

最近好厌学,主要是对这个冬季学校不感兴趣,还想多陪陪家人,家里很温暖,但是又没有暂缓返校的理由,也许是时候宣告开学了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值