1. 程式人生 > >1095 解碼PAT准考證——C++實現

1095 解碼PAT准考證——C++實現

題目

1095 解碼PAT准考證 (25 分)

PAT 准考證號由 4 部分組成:

  • 第 1 位是級別,即 T 代表頂級;A 代表甲級;B 代表乙級;
  • 第 2~4 位是考場編號,範圍從 101 到 999;
  • 第 5~10 位是考試日期,格式為年、月、日順次各佔 2 位;
  • 最後 11~13 位是考生編號,範圍從 000 到 999。

現給定一系列考生的准考證號和他們的成績,請你按照要求輸出各種統計資訊。

輸入格式:

輸入首先在一行中給出兩個正整數 N(≤10​4​​)和 M(≤100),分別為考生人數和統計要求的個數。

接下來 N 行,每行給出一個考生的准考證號和其分數(在區間 [0,100] 內的整數),其間以空格分隔。

考生資訊之後,再給出 M 行,每行給出一個統計要求,格式為:型別 指令,其中

  • 型別 為 1 表示要求按分數非升序輸出某個指定級別的考生的成績,對應的 指令 則給出代表指定級別的字母;
  • 型別 為 2 表示要求將某指定考場的考生人數和總分統計輸出,對應的 指令 則給出指定考場的編號;
  • 型別 為 3 表示要求將某指定日期的考生人數分考場統計輸出,對應的 指令 則給出指定日期,格式與准考證上日期相同。

輸出格式:

對每項統計要求,首先在一行中輸出 Case #: 要求,其中 # 是該項要求的編號,從 1 開始;要求 即複製輸入給出的要求。隨後輸出相應的統計結果:

  • 型別 為 1 的指令,輸出格式與輸入的考生資訊格式相同,即 准考證號 成績。對於分數並列的考生,按其准考證號的字典序遞增輸出(題目保證無重複准考證號);
  • 型別 為 2 的指令,按 人數 總分 的格式輸出;
  • 型別 為 3 的指令,輸出按人數非遞增順序,格式為 考場編號 總人數。若人數並列則按考場編號遞增順序輸出。

如果查詢結果為空,則輸出 NA

輸入樣例:

8 4
B123180908127 99
B102180908003 86
A112180318002 98
T107150310127 62
A107180908108 100
T123180908010 78
B112160918035 88
A107180908021 98
1 A
2 107
3 180908
2 999

輸出樣例:

Case 1: 1 A
A107180908108 100
A107180908021 98
A112180318002 98
Case 2: 2 107
3 260
Case 3: 3 180908
107 2
123 2
102 1
Case 4: 2 999
NA

演算法

因為型別1,3兩個輸出的排序規則類似,構建一個結構體陣列分別來儲存學生和考場的情況。其中學生儲存的是准考證號和成績,考場儲存的是考場編號和人數。建立兩個結構體陣列stu和dat。stu按考生等級將考生分為3類分別儲存。dat按日期將考場分別儲存。再建立三個map:Nm,Sm,Dm。Nm記錄每個考場出現的次數,Sm記錄每個考場的總分。Dm記錄每個日期,每增加一個日期對應的Key值為上一個日期對應的key值加1,每個日期的key值就可以作為dat陣列的下標。最後對應3種類型分別排序輸出。

注意:

1.使用scanf,printf輸入輸出。

2.型別2輸出中考場的人數為該考場出現的總次數,而型別3輸出中考場的人數為對應日期的考場出現的次數。

3.dat陣列應定義為動態陣列,否則容易產生段錯誤。
 

程式碼

#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<map>
using namespace std;
 
struct StudentOrHall
{
	string id;                                                                            //stu陣列中為準考證號,dat陣列中為考場編號
	int number;                                                                           //stu陣列中為考生成績,dat陣列中為考場人數
};
 
bool cmp(struct StudentOrHall s1, struct StudentOrHall s2)
{
	if (s1.number != s2.number) return s1.number > s2.number;
	return s1.id < s2.id;
}
 
int main()
{
	int n, m, i, j, k = 1, score, date, command;
	vector<struct StudentOrHall> stu[3];
	vector<vector<struct StudentOrHall>> dat;
	string Hid, level = "TAB";
	char Sid[13], s[6];
	scanf("%d %d", &n, &m);
	map<string, int> Nm, Sm;
	map<int, int> Dm;
	for (i = 0; i < n; i++)
	{
		scanf("%s %d", &Sid, &score);
		stu[level.find(Sid[0])].push_back({ Sid,score });
		Hid = string(Sid).substr(1, 3);
		date = stoi(string(Sid).substr(4, 6));
		if (!Dm[date]) Dm[date] = k++;                                                     //設定每個日期在dat陣列中對應的下標
		dat.resize(k);                                                                     //動態調整dat陣列大小
		for (j = 0; j < dat[Dm[date] - 1].size() && dat[Dm[date] - 1][j].id != Hid; j++);  //判斷該日期相應考場編號是否出現過
		if (j == dat[Dm[date] - 1].size()) dat[Dm[date] - 1].push_back({ Hid,0 });         
		dat[Dm[date] - 1][j].number++;                                                     //該日期相應考場的人數+1
		Nm[Hid]++;                                                                         //考場的總人數
		Sm[Hid] += score;                                                                  //考場的總成績
	}
	for (i = 0; i < m; i++)
	{
		scanf("%d %s", &command, &s);
		printf("Case %d: %d %s\n", i + 1, command, s);
		if (command == 1)
		{
			command = level.find(s[0]);
			sort(stu[command].begin(), stu[command].end(), cmp);
			for (j = 0; j < stu[command].size(); j++)
				printf("%s %d\n", stu[command][j].id.c_str(), stu[command][j].number);
			if (!j) printf("NA\n");
		}
		else if (command == 2)
		{
			if (Nm[s]) printf("%d %d\n", Nm[s], Sm[s]);
			else printf("NA\n");
		}
		else
		{
			command = stoi(s);
			if (!Dm[command]) printf("NA\n");
			else
			{
				sort(dat[Dm[command] - 1].begin(), dat[Dm[command] - 1].end(), cmp);
				for (j = 0; j < dat[Dm[command] - 1].size(); j++)
					printf("%s %d\n", dat[Dm[command] - 1][j].id.c_str(), dat[Dm[command] - 1][j].number);
			}
		}
	}
	return 0;
}