【题解】高考排名

高考排名

- R a n k i n g Ranking Ranking

I   w a s   e v e r   a   f i g h t e r ,   s o ,   o n e   f i g h t   m o r e ,   t h e   b e s t   a n d   t h e   l a s t . I \ was \ ever \ a \ fighter, \ so, \ one \ fight \ more, \ the \ best \ and \ the \ last. I was ever a fighter, so, one fight more, the best and the last.

1. D e s c r i b e 1.Describe 1.Describe

高考成绩的排名规则是按总分由高到低排,总分相同的人排名应相同,例如有 5 5 5 个同学的高考成绩:

考号姓名成绩
001 001 001 c 1 c1 c1 567 567 567
002 002 002 y g h ygh ygh 605 605 605
003 003 003 g l gl gl 690 690 690
004 004 004 x t b xtb xtb 605 605 605
005 005 005 w z s wzs wzs 567 567 567

按照成绩排序后,成绩如下:

排名考号姓名成绩
1 1 1 003 003 003 g l gl gl 690 690 690
2 2 2 002 002 002 y g h ygh ygh 605 605 605
2 2 2 004 004 004 x t b xtb xtb 605 605 605
3 3 3 001 001 001 c 1 c1 c1 567 567 567
3 3 3 005 005 005 w z s wzs wzs 567 567 567

现在给出 n n n 个同学的高考成绩信息,请你回答查询:考号为 xxx 的学生排名是多少。

输入第一行含一个整数 n n n,表示学生人数。
接下来的 n n n 行,每行表示一个学生信息:考号(长度为 6 6 6 的数字串),姓名(长度不超过 10 10 10,且不空格的字符串),成绩(是在 0 ⋯ 750 0\cdots 750 0750 之间的整数)。
n + 2 n+2 n+2 行为一个整数 m m m,表示有 m m m 次查询。接下来的 m m m 行,每行是一个考号信息。

输出包含 m m m 行,对应输入中的查询。如果找到对应考号的学生,输出其姓名和名次,否则输出“ T e s t   e r r o r   n u m b e r ! Test \ error \ number! Test error number!”。

2. S a m p l e 2.Sample 2.Sample

( i n p u t ) (input) (input)

5
001 cl 567
002 ygh 605
003 gl 690
004 xtb 605
005 wzs 567
3
003
001
006

( o u t p u t ) (output) (output)

gl 1
cl 3
Test error number!

3. S o l u t i o n 3.Solution 3.Solution

这道题用的是 S T L STL STL。(废话)

我的方法是用 m a p map map (映射)和 p r i o r i t y   q u e u e priority \ queue priority queue (优先队列) 。

在输入的过程中,由于要进行排序,马上就会想到优先队列。在最后的输出时,学号和下标存在键-值的对应关系,可以用 m a p map map

我的代码(别急):

#include <cstdio>
#include <algorithm>
#include <queue>
#include <string>
#include <map>
#include <iostream>
#pragma GCC optimize(2)
using namespace std;
struct student {
	string number;
	char name[15];
	int grades, order, id;
//	int text;
	bool operator<(const student& x)const {
		return grades < x.grades;
	}
} a[100005];
//bool cmp(student x, student y) {
//	return x.grades > y.grades;
//}
map<string, int> g;
priority_queue<student, vector<student>, less<student> > pq;
int main() {
	ios::sync_with_stdio(false);
	int n;
	cin >> n;
	for(int i = 1; i <= n; i ++) {
		cin >> a[i].number >> a[i].name >> a[i].grades;
		a[i].id = i;
		g[a[i].number] = i;
//		cout << "map:" << g[a[i].number] << " ";
		pq.push(a[i]);
	}
//	cout << endl;
	int tmp = 0;
	int id;
	while(!pq.empty()) {
		if(pq.top().grades != tmp) {
			id ++;
			a[pq.top().id].order = id;
		}
		else {
			a[pq.top().id].order = id;
		}
		tmp = pq.top().grades;
//		a[i].text = tmp;
		pq.pop();
	}
//	for(int i = 1; i <= n; i ++) {
//		cout << "order:" << a[i].order << " ";
//	}
//	cout << endl;
	int q;
	cin >> q;
	while(q --) {
		string s;
		cin >> s;
//		cout << "map:" << g[s] << " ";
		g[s] ? cout << a[g[s]].name << " " << a[g[s]].order << endl : cout << "Test error number!" << endl;
	}
	return 0;
}

(注释有点多)

我们分开来讲。

p a r t   I part\ I part I
struct student {
	string number; //学号
	char name[15]; //姓名
	int grades, order, id; //成绩,排名后的名次,输入时的下标。
//	int text;
	bool operator<(const student& x)const { //重载运算符
		return grades < x.grades;
	}
} a[100005];

这里设置了变量 i d id id,因为之后会进行排序,通过 i d id id 可以还原原数组。

这里也有重载运算符操作,主要是方便后面优先队列的排序。

p a r t   I I part \ II part II
map<string, int> g; //映射
priority_queue<student, vector<student>, less<student> > pq; //优先队列

map<string, int> g 通俗讲就是下标类型为 string 而数据类型为 int (一个字符串对应一个整数)。这里下标为学号,存的是下标(学号)在原数组里的下标。

比如说一个人叫 张三,他是第 3 3 3 输入的,则 g[张三]=3

priority_queue<student, vector<student>, less<student> > pq 可以看做一个可以排序的队列,push 一个就找个合适的地方存放。其中 less 表示从大到小,此外还有从小到大的 greater

p a r t   I I I part \ III part III
	for(int i = 1; i <= n; i ++) {
		cin >> a[i].number >> a[i].name >> a[i].grades;
		a[i].id = i;
		g[a[i].number] = i;
//		cout << "map:" << g[a[i].number] << " ";
		pq.push(a[i]);
	}

输入。

a[i].id = i ,备份下标。
g[a[i].number] = i; ,建立对应关系。
pq.push(a[i]) ,插入元素,同时排序。

p a r t   I V part\ IV part IV
	int tmp = 0;
	int id;
	while(!pq.empty()) {
		if(pq.top().grades != tmp) {
			id ++;
			a[pq.top().id].order = id;
		}
		else {
			a[pq.top().id].order = id;
		}
		tmp = pq.top().grades;
//		a[i].text = tmp;
		pq.pop();
	}

排名。

相当于把队列里的一个一个拎出来。

tmp 表示一个被比较的数(上一个人考的分数),当这个人和上一个人考的一样,他的排名就应该和上一个人一样,反之是上一个人的排名加 1 1 1。之后将这个人考的分数赋值给 tmp,继续比较。

注意:

a[pq.top().id] ,在这里之前备份的下标有用了。

p a r t   V part\ V part V
	int q;
	cin >> q;
	while(q --) {
		string s;
		cin >> s;
//		cout << "map:" << g[s] << " ";
		g[s] ? cout << a[g[s]].name << " " << a[g[s]].order << endl : cout << "Test error number!" << endl;
	}

输出。

询问一个学号,输出对应的姓名和排名,这里 g[s] 对应的是原数组的对应下标,如果 g[s] 0 0 0 的话,说明 s 未与任何人对应,即没有该考生的信息,输出 T e s t   e r r o r   n u m b e r ! Test \ error \ number! Test error number!

提示:

O2 是要开的。

( b e f o r e ) (before) (before)
屏幕截图 2022-05-01 220029.png
( a f t e r ) (after) (after)

屏幕截图 2022-05-01 220133.png
显而易见。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
06-01
这道题是一道典型的费用限制最短路题目,可以使用 Dijkstra 算法或者 SPFA 算法来解决。 具体思路如下: 1. 首先,我们需要读入输入数据。输入数据中包含了道路的数量、起点和终点,以及每条道路的起点、终点、长度和限制费用。 2. 接着,我们需要使用邻接表或邻接矩阵来存储图的信息。对于每条道路,我们可以将其起点和终点作为一个有向边的起点和终点,长度作为边权,限制费用作为边权的上界。 3. 然后,我们可以使用 Dijkstra 算法或 SPFA 算法求解从起点到终点的最短路径。在这个过程中,我们需要记录到每个点的最小费用和最小长度,以及更新每条边的最小费用和最小长度。 4. 最后,我们输出从起点到终点的最短路径长度即可。 需要注意的是,在使用 Dijkstra 算法或 SPFA 算法时,需要对每个点的最小费用和最小长度进行松弛操作。具体来说,当我们从一个点 u 经过一条边 (u,v) 到达另一个点 v 时,如果新的费用和长度比原来的小,则需要更新到达 v 的最小费用和最小长度,并将 v 加入到优先队列(Dijkstra 算法)或队列(SPFA 算法)中。 此外,还需要注意处理边权为 0 或负数的情况,以及处理无法到达终点的情况。 代码实现可以参考以下样例代码: ```c++ #include <cstdio> #include <cstring> #include <queue> #include <vector> using namespace std; const int MAXN = 1005, MAXM = 20005, INF = 0x3f3f3f3f; int n, m, s, t, cnt; int head[MAXN], dis[MAXN], vis[MAXN]; struct Edge { int v, w, c, nxt; } e[MAXM]; void addEdge(int u, int v, int w, int c) { e[++cnt].v = v, e[cnt].w = w, e[cnt].c = c, e[cnt].nxt = head[u], head[u] = cnt; } void dijkstra() { priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q; memset(dis, 0x3f, sizeof(dis)); memset(vis, 0, sizeof(vis)); dis[s] = 0; q.push(make_pair(0, s)); while (!q.empty()) { int u = q.top().second; q.pop(); if (vis[u]) continue; vis[u] = 1; for (int i = head[u]; i != -1; i = e[i].nxt) { int v = e[i].v, w = e[i].w, c = e[i].c; if (dis[u] + w < dis[v] && c >= dis[u] + w) { dis[v] = dis[u] + w; q.push(make_pair(dis[v], v)); } } } } int main() { memset(head, -1, sizeof(head)); scanf("%d %d %d %d", &n, &m, &s, &t); for (int i = 1; i <= m; i++) { int u, v, w, c; scanf("%d %d %d %d", &u, &v, &w, &c); addEdge(u, v, w, c); addEdge(v, u, w, c); } dijkstra(); if (dis[t] == INF) printf("-1\n"); else printf("%d\n", dis[t]); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值