PTA 10-排序5 PAT Judge
原题链接
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 (≤10^4), the total number of users, K (≤5), the total number of problems, and M (≤10^5 ), 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 -
结尾无空行
思路
一开始也没思路,参考了博主的代码写的
https://blog.csdn.net/xijujie/article/details/53157967
1.建立结构体{每个问题的得分数组、总分、完美解决问题的数量}
2.用fullsore[]数组来存储K各题目的满分
3.利用vector ranklist结合自己写的cmp函数+stl中的sort函数,用来根据题意排序,并按照排名rank存储到vector ranklist中,存储的是结构体数组的i下标
4.以id为下标存储结构体,若id为00002,则结构体存在users[00002]
5.读每一行submission的值,若users[id]是第一次建立,创建新的结构体结点,初始化各项的值,若不是第一次建立,则判断这次输入的pnum(问题号+1)的pscore与原来存储的这个问题的score进行比较,大于的话则更新score
6.利用flag标记这个同学是不是“全部没做或者全部complieError”
情况,是的话,根据题意不用打印出来,即不用加入得到vector中
7.更新每个结构体的perfect值和total值
8.遍历排序后的vector ranklist的值,使用ranknum来表示rank,用max_total_score来记录上一个id的作者的总分,若这个id作者的总分比上一个id作者总分小,则排名ranknum=i+1
;这里非常巧妙,因为即使有同分,当出现不同分时排名总是和所有id的总分都不同是一致的,(所有id的总分都不同时的rank都是下标+1)
注意
1.结构体初始化
一开始users[id]的每项问题的score初始化的-2,原因
(1)complieError是-1,若标记为-1则不能判断这个id的同学有没有尝试过做这一题,只是最后编译错误而已。
(2)只要score大,则更新,所以初始化的值要比complieError(-1)的值要小,这样才能记录complieError的情况。
2.结构体数组的下标
可以从题目中摸索到开始的编号为00001,若有N个人则编号为(00001+N),所以要遍历数组可以用下标1——N。
for(int i=1;i<=N;i++)
Code
#include<iostream>
#include<vector>
#include<algorithm>
#define MaxPerson 10010
#define MaxK 6
using namespace std;
int N,K,M;//N个人,K个问题,M个提交
struct userNode{
int *score;//各个问题的得分
int total;//总分,初始化为0
int perfect;//完美解决问题的数量
};
userNode *users[MaxPerson];
bool cmp(int a,int b){
if(users[a]->total>users[b]->total){//总分优先
return true;
}else if(users[a]->total==users[b]->total){//总分相同比较perfect数
if(users[a]->perfect>users[b]->perfect){//完美解决问题的数量优先
return true;
}else if(users[a]->perfect==users[b]->perfect){//perfect数相同比较id的大小,小的排前
if(a<b){
return true;
}
}
}
return false;
}
int main(){
scanf("%d %d %d",&N,&K,&M);
int fullsore[K];//记录问题总分
int id,pnum,pscore;
for(int i=0;i<K;i++){
scanf("%d",&fullsore[i]);//注意Problems_fullsore下标是0,但是问题从1开始
}
vector<int> ranklist;//用来排序最后的rank
for(int i=0;i<M;i++){
scanf("%d %d %d",&id,&pnum,&pscore);
if(!users[id]){//id第一次建立->初始化各项的值
users[id]=new userNode;
users[id]->score=new int[K];
for(int j=0;j<K;j++){
users[id]->score[j]=-2;//没有交过,用-2做标记 why-2?因为complieError是-1
}
users[id]->total=0;
users[id]->perfect=0;
}
if(users[id]->score[pnum-1]<pscore){
users[id]->score[pnum-1]=pscore;
}
}
for(int i=1;i<=N;i++){
if(users[i]){
int flag=0;
for(int j=0;j<K;j++){
if(users[i]->score[j]==fullsore[j]){
users[i]->perfect++;
}
if(users[i]->score[j]>=0){
flag=1;//不是全部没做或者全部complieError
users[i]->total+=users[i]->score[j];
}
}
if(flag){//有资格去排名
ranklist.push_back(i);
}
}
}
sort(ranklist.begin(),ranklist.end(),cmp);//以函数cmp的规则去对ranklist排序
int ranknum=0,max_total_score=0,newid;
for(int i=0;i<K;i++){
max_total_score+=fullsore[i];//初始化当前最大的总分
}
for(int i=0;i<ranklist.size();i++){
newid=ranklist[i];//当前出来的id
if(users[newid]->total<max_total_score){
ranknum=i+1;//如果排名相同的话ranknum不会变,不相同时变成下标+1{非常巧妙}
max_total_score=users[newid]->total;
}
printf("%d %05d %d",ranknum,newid,max_total_score);
for(int j=0;j<K;j++){
if(users[newid]->score[j]==-2){//没有提交过
printf(" -");
}else if(users[newid]->score[j]==-1){//提交过但是编译错误
printf(" 0");
}else{
printf(" %d",users[newid]->score[j]);
}
if(i!=ranklist.size()&&j==K-1){
printf("\n");
}
}
}
return 0;
}