Problem Description
The ranklist of PAT is generated from the status list, which shows the scores of the submissions. This time you are supposed to generate the ranklist for PAT.
Input Specification
Each input file contains one test case. For each case, the first line contains 3 positive integers, N (≤104), the total number of users, K (≤5), the total number of problems, and M (≤105), the total number of submissions. It is then assumed that the user id's are 5-digit numbers from 00001 to N, and the problem id's are from 1 to K. The next line contains K positive integers p[i] (i=1, ..., K), where p[i] corresponds to the full mark of the i-th problem. Then M lines follow, each gives the information of a submission in the following format:
user_id problem_id partial_score_obtained
where partial_score_obtained is either −1 if the submission cannot even pass the compiler, or is an integer in the range [0, p[problem_id]]. All the numbers in a line are separated by a space.
Output Specification
For each test case, you are supposed to output the ranklist in the following format:
rank user_id total_score s[1] ... s[K]
where rank is calculated according to the total_score, and all the users with the same total_score obtain the same rank; and s[i] is the partial score obtained for the i-th problem. If a user has never submitted a solution for a problem, then "-" must be printed at the corresponding position. If a user has submitted several solutions to solve one problem, then the highest score will be counted.
The ranklist must be printed in non-decreasing order of the ranks. For those who have the same rank, users must be sorted in nonincreasing order according to the number of perfectly solved problems. And if there is still a tie, then they must be printed in increasing order of their id's. For those who has never submitted any solution that can pass the compiler, or has never submitted any solution, they must NOT be shown on the ranklist. It is guaranteed that at least one user can be shown on the ranklist.
Sample Input
7 4 20
20 25 25 30
00002 2 12
00007 4 17
00005 1 19
00007 2 25
00005 1 20
00002 2 2
00005 1 15
00001 1 18
00004 3 25
00002 2 25
00005 3 22
00006 4 -1
00001 2 18
00002 1 20
00004 1 15
00002 4 18
00001 3 4
00001 4 2
00005 2 -1
00004 2 0
Sample Output
1 00002 63 20 25 - 18
2 00005 42 20 0 22 -
2 00007 42 - 25 - 17
2 00001 42 18 18 4 2
5 00004 40 15 0 25 -
Solution
题意理解:读入用户的提交后排序输出 OJ 排名。
先看用例,
- 第一行是三个整数:N 表示用户数,每个用户从 1 到 N 编号;K 表示题目数;M 表示提交数。
- 第二行是 K 个整数,表示每题的满分,存在
p[i]中。 - 第三行开始往下 M 行是提交。
构造用来排序的结构体数组,包括 ID 、总分、满分题数、各题得分数组,
id为用户 ID ,是一个整数total为用户总分,是一个整数full为用户获得满分的题目数量,是一个整数s[i]为用户每题得分,i表示第i题,下标从 1 开始
完整代码(代码详解在后面):
#include <stdio.h>
#include <stdlib.h>
struct user{
int id;
int total;
int full;
int s[6];
};
void Submmit(int *N, int *K, int *M, int p[], struct user A[])
{
int i, j, id, num, score;
scanf("%d%d%d", N, K, M);
for (i = 1; i <= *K; i++) scanf("%d", &p[i]);
for (i = 0; i < *N; i++) {
A[i].id = i + 1;
A[i].total = 0;
A[i].full = 0;
for (j = 1; j <= *K; j++) {
A[i].s[j] = -2;
}
}
for (i = 0; i < *M; i++) {
scanf("%d%d%d", &id, &num, &score);
if (score > A[id - 1].s[num]) A[id - 1].s[num] = score;
}
for (i = 0; i < *N; i++) {
for (j = 1; j <= *K; j++) {
if (A[i].s[j] > 0) A[i].total += A[i].s[j];
if (A[i].s[j] == p[j]) A[i].full++;
}
}
}
int NeverSubmmit(struct user a, int K)
{
int i, flag = 1;
for (i = 1; i <= K && flag; i++) {
if (a.s[i] > -1) flag = 0;
}
return flag;
}
void Rank(int N, int K, struct user A[])
{
int i, j, rank = 1, tie = 0, curscore = -1;
for (i = 0; i < N; i++) {
if (curscore != A[i].total) {
rank += tie;
curscore = A[i].total;
tie = 0;
}
tie++;
if (!NeverSubmmit(A[i], K)) {
printf("%d %05d %d", rank, A[i].id, A[i].total);
for (j = 1; j <= K; j++)
if (A[i].s[j] > -1) printf(" %d", A[i].s[j]);
else if (A[i].s[j] == -1) printf(" 0");
else printf(" -");
printf("\n");
}
}
}
int cmp(const void *a, const void *b)
{
struct user *usera = (struct user*)a;
struct user *userb = (struct user*)b;
if (usera->total != userb->total) return userb->total - usera->total;
else if (usera->full != userb->full) return userb->full - usera->full;
else return usera->id - userb->id;
}
int main()
{
int N, K, M;
int p[6];
struct user A[10000];
Submmit(&N, &K, &M, p, A);
qsort(A, N, sizeof(struct user), cmp);
Rank(N, K, A);
return 0;
}
程序框架:
- 1️⃣ 读入用例
- 2️⃣ 进行排序
- 3️⃣ 输出排名
1️⃣ 读入用例,
- 读入 N 、 K 、 M
- 根据 K 读入
p[i]下标从 1 开始,到 K 结束 - 根据 N 读入用户数组
A[i],下标从 0 开始,到 N - 1 结束(为了使用 qsort)id初始化为i + 1total与full初始化为 0- 每个
A[i]的s[j]初始化为 -2 ,表示没有提交过
- 根据 M 读入提交,如果
score比s[j]大就更新s[j]- 如果
s[j]> -1 表示有成绩 - 如果
s[j]== -1 表示提交了但编译错误 - 如果
s[j]== -2 表示完全没有提交
- 如果
- 全部输入读完以后,遍历
A[i]计算对应的total与full
2️⃣ 进行排序,
- 使用
qsort库函数进行快速排序,传入参数为待排序数组、数组大小、数组元素所占字节数、排序方法- 排序方法函数为返回值为
int的函数,传入参数为两个const void*形式参数 - 返回值小于 0 表示左形参排在右形参前面(数组下标小为前大为后)
- 返回值大于 0 表示右形参排在左形参前面(数组下标小为前大为后)
- 排序方法函数为返回值为
3️⃣ 输出排名,
- 根据已经排好序的
A[i],同分的为并列名次- 先初始化
rank为 1 ,tie为 0 ,curscore为 -1 - 如果当前分数与
curscore不同,rank更新为原来的基础上加上平局的人数,即tie,同时把tie归零 - 每遍历一个用户就要把
tie加 1
- 先初始化
- 判断更新完
rank后判断该用户是否从来没提交过有效答案,如果提交过,在排名里输出,否则不输出- 如果用户的
s[i]中没有一个大于 -1 的分数,说明要么全是从未提交,要么最多只有编译错误的提交,判定为不输出
- 如果用户的
- 输出用户每题分数时,对每题分数进行遍历输出
- 如果
s[i]大于 -1 ,直接输出分数,为一个整数 - 如果
s[i]为 -1 ,输出 0 分,虽然此题只提交了编译错误的代码但作为登上排名的题目不算做从未提交 - 如果
s[i]为 -2 ,输出 - ,因为从未提交过
- 如果