浙江大学数据结构MOOC-课后习题-第十讲-排序5 PAT Judge【未完成】

题目汇总
浙江大学数据结构MOOC-课后习题-拼题A-代码分享-2024

题目描述

这段文字是关于如何生成PAT(一种编程能力测试)的排行榜的说明。下面是这段文字的中文翻译:

输入说明:

每个输入文件包含一个测试案例。对于每个案例,第一行包含三个正整数,N(不超过10^4) ,表示用户总数;K(不超过5),表示问题的总数;M(不超过10^5),表示提交的总数。假定用户ID是5位数的数字,从00001到N,问题ID是从1到K。接下来的一行包含K个正整数,其中每个数字p[i]表示第i个问题的最高分数。然后是M行,每行提供一次提交的信息,格式如下:
user_id problem_id partial_score_obtained

其中partial_score_obtained是以下两种情况之一:如果提交不能通过编译器,则为-1;或者是一个整数,在[0, p[problem_id]]范围内。一行中的所有数字由空格分隔。

输出说明:

对于每个测试案例,需要按照以下格式输出排行榜:
rank user_id total_score s[1] ... s[K]

其中rank是按照total_score计算的排名,如果total_score相同,则获得相同的rank ;total_score是用户的总分数;s[i]是用户在第i个问题上获得的部分分数 。如果用户从未提交 过针对某个问题的解决方案,或者该解决方案没有通过 编译器,则相应位置打印"-" 。如果用户针对一个问题提交了多个 解决方案,则只计算最高分数 。排行榜必须按照排名的非递减顺序打印 。如果排名相同 ,用户必须根据完全解决问题的数量 按递减顺序排序。如果仍然有平局 ,则必须按照他们的ID递增顺序 打印。那些从未提交过 可以通过编译器的解决方案,或者从未提交过任何解决方案的用户,将不会出现在排行榜上。保证至少有一个用户会出现在排行榜上。

代码展示

做不动了...还有一天就要关闭答题咯,等后面有机会再完善吧:( sad

cpp 复制代码
/*
	利用多关键字排序的思想:
	先按分数排顺序
	然后按照解决问题的数量来排序
	最后按照ID来排序
*/

#include <iostream>
#include <string>
#define neverSubmit -1
#define MAX_PROBLEM 6
#define MAX_USERS 10001
#define MAX_SUBMITS 100000
/* 输入信息 */
//struct inputInfo
//{
//	std::string user_id;
//	int problem_id;
//	int partial_score_obtained;
//};
/* 用户个人信息 */
struct userInfo
{	
	int rank = -1;						/* 排名 */
	std::string user_id;				/* ID */
	int nSolve = 0;						/* 完全解决问题的数量 */
	int score[MAX_PROBLEM] = {-1, -1, -1, -1, -1}; /* 每道题得分情况-存储历史最大得分 -1表示未提交/未通过编译 */
	int sumScore;					/* 总分 */
	userInfo* Next = NULL;
	userInfo* Pre = NULL;
};
/* 表头数组类型 */
struct bucket
{
	userInfo* First = NULL;
	userInfo* Last = NULL;
};
/* 获取个位数字 */
int getLow(int score)
{
	return score % 10;
}
/* 获取十位数字 */
int getMid(int score)
{
	int temp = score / 10;
	return temp % 10;
}
/* 获取百位数字 */
int getHigh(int score)
{
	return score / 100;
}
/* 获取用户信息 */
void getUserInfo(int N, int K, int M, int P[], userInfo user[])
{	
	std::string user_id;
	int problem_id;
	int partial_score_obtained;
	/* 统计每位用户每道题所得最高分 */
	for (int i = 0; i < M; i++)
	{
		std::cin >> user_id >> problem_id >> partial_score_obtained;
		int id = std::stoi(user_id);
		user[id].user_id = user_id;
		/* 将输入的信息存于用户个人信息中 */
		if (partial_score_obtained >= 0 && partial_score_obtained <= P[problem_id])
		{
			/* 如果本次提交大于最大值则更新 */
			int maxScore = user[id].score[problem_id];
			if (partial_score_obtained > maxScore)
				user[id].score[problem_id] = partial_score_obtained;
		}
	}
	/* 计算每位用户所得总分 和 完全解决的问题个数 */
	for (int i = 1; i <= N; i++)
	{	
		user[i].sumScore = 0;
		user[i].nSolve = 0;
		for (int j = 1; j <= K; j++)
		{	
			if (user[i].score[j] != -1)
			{
				user[i].sumScore += user[i].score[j];
				if (user[i].score[j] == P[j])
					user[i].nSolve++;
			}

		}
	}
}
/* 复制用户信息 */
void copy(userInfo* SRC, userInfo* ORI, int K)
{
	SRC->rank = ORI->rank;
	SRC->sumScore = ORI->sumScore;
	SRC->user_id = ORI->user_id;
	for (int i = 0; i < K; i++)
		SRC->score[i] = ORI->score[i];
}
/* 按照分数进行基数排序 */
void scoreSort(int N, int K, int P[], userInfo user[], bucket highScoreArray[])
{
	/* 先对分数由高到低排序 基数:10 */
	bucket lowScoreArray[9];
	/* 低位排序 */
	for (int i = 1; i <= N; i++)
	{	/* low取值范围0到9 */
		int low = getLow(user[i].sumScore);
		/* 存进对应桶的末尾 */
		userInfo* newNode = (userInfo*)malloc(sizeof(userInfo));
		newNode->rank = user[i].rank;
		newNode->sumScore = user[i].sumScore;
		newNode->user_id = user[i].user_id;
		for (int i = 0; i < K; i++)
			newNode->score[i] = user[i].score[i];
		/*copy(newNode, &user[i], K);*/
		newNode->Next = NULL;
		newNode->Pre = NULL;
		/* 表头不为空且仅有一个元素 */
		if (lowScoreArray[low].First && lowScoreArray[low].First == lowScoreArray[low].Last)
		{	
			lowScoreArray[low].First->Next = newNode;
			newNode->Pre = lowScoreArray[low].First;
			lowScoreArray[low].Last = newNode;
		}
		/* 表不为空且不止一个元素 */
		else if(lowScoreArray[low].First && lowScoreArray[low].First != lowScoreArray[low].Last)
		{
			lowScoreArray[low].Last->Next = newNode;
			newNode->Pre = lowScoreArray[low].Last;
			lowScoreArray[low].Last = newNode;
		}
		/* 表为空 */
		else
		{	
			lowScoreArray[low].First = newNode;
			lowScoreArray[low].Last = newNode;
			newNode->Pre = NULL;
		}
		
	}
	/* 中位排序 */
	bucket midScoreArray[9];
	/* 按顺序从lowScoreArray中取出元素 */
	userInfo* newNode = lowScoreArray[0].First;
	int count = 0;
	int j = 0;
	while(count != N)
	{
		while(newNode == NULL && j < 9)
			newNode = lowScoreArray[++j].First; /* 找到第一个不为空的表头 */
		/* 从lowScoreArray中取出元素 */
		/* 表头不为空且仅有一个元素 */
		if (lowScoreArray[j].First != NULL && lowScoreArray[j].First == lowScoreArray[j].Last )
			lowScoreArray[j].First = lowScoreArray[j].Last = NULL;
		/* 若表中不止一个元素 */
		else if(lowScoreArray[j].First != NULL && lowScoreArray[j].First != lowScoreArray[j].Last)
			lowScoreArray[j].First = newNode->Next;
		
		count++;/* 统计排序的元素个数 */
			
		/* 存进对应桶的末尾 */
		int mid = getMid(newNode->sumScore);	/* 获取第二位置的值 */
		newNode->Next = NULL;
		newNode->Pre = NULL;
		/* 表头不为空且仅有一个元素 */
		if (midScoreArray[mid].First && midScoreArray[mid].First == midScoreArray[mid].Last)
		{
			midScoreArray[mid].First->Next = newNode;
			newNode->Pre = midScoreArray[mid].First;
			midScoreArray[mid].Last = newNode;
		}
		/* 表不为空且不止一个元素 */
		else if (midScoreArray[mid].First && midScoreArray[mid].First != midScoreArray[mid].Last)
		{
			midScoreArray[mid].Last->Next = newNode;
			newNode->Pre = midScoreArray[mid].Last;
			midScoreArray[mid].Last = newNode;
		}
		/* 表为空 */
		else
		{
			midScoreArray[mid].First = newNode;
			midScoreArray[mid].Last = newNode;
			newNode->Pre = NULL;
		}
		newNode = newNode->Next;	
	}

	/* 高位排序 */
	/* 按顺序从lowScoreArray中取出元素 */
	newNode = midScoreArray[0].First;
	count = 0;
	j = 0;
	while (count != N)
	{
		while (newNode == NULL && j < 9)
			newNode = midScoreArray[++j].First; /* 找到第一个不为空的表头 */
		/* 从midScoreArray中取出元素 */
		/* 表头不为空且仅有一个元素 */
		if (midScoreArray[j].First != NULL && midScoreArray[j].First == midScoreArray[j].Last)
			midScoreArray[j].First = midScoreArray[j].Last = NULL;
		/* 若表中不止一个元素 */
		else if (midScoreArray[j].First != NULL && midScoreArray[j].First != midScoreArray[j].Last)
			midScoreArray[j].First = newNode->Next;

		count++;/* 统计排序的元素个数 */

		/* 存进对应桶的末尾 */
		int high = getHigh(newNode->sumScore);	/* 获取第二位置的值 */
		newNode->Next = NULL;
		newNode->Pre = NULL;
		/* 表头不为空且仅有一个元素 */
		if (highScoreArray[high].First && highScoreArray[high].First == highScoreArray[high].Last)
		{
			highScoreArray[high].First->Next = newNode;
			newNode->Pre = midScoreArray[high].First;
			highScoreArray[high].Last = newNode;
		}
		/* 表不为空且不止一个元素 */
		else if (highScoreArray[high].First && highScoreArray[high].First != highScoreArray[high].Last)
		{
			highScoreArray[high].Last->Next = newNode;
			newNode->Pre = midScoreArray[high].Last;
			highScoreArray[high].Last = newNode;
		}
		/* 表为空 */
		else
		{
			highScoreArray[high].First = newNode;
			highScoreArray[high].Last = newNode;
		}
		newNode = newNode->Next;
	}
}
/* 获取排名 */
void getRank(int N, bucket scoreArray[])
{	
	/* 按顺序从scoreArray中读取元素 */
	int i = 9;
	bool flag = false;
	userInfo* preNode = NULL;
	userInfo* newNode = NULL;
	int preIndex;
	/* 找到最后一个节点 */
	for (newNode = scoreArray[i].Last; i >= 0;)
	{
		if (flag == false && newNode == NULL)
		{
			newNode = scoreArray[--i].Last;
		}
		else
		{	
			preNode = newNode;
			preIndex = i;
			break;
		}
	}
	/* 排序 */
	flag = false;
	int preRank; 
	int preScore;
	int count = 0;
	newNode = preNode;
	while(count <= N)
	{	
		/* 检查当前节点是否为空 */
		while (newNode == NULL)
		{	
			if (preIndex > 0)
			{
				newNode = scoreArray[--preIndex].Last;
			}
			else return;
		}
		/* 对第一个元素特殊处理 */
		if (flag == false)
		{
			newNode->rank = 1;
			preRank = 1;
			preScore = newNode->sumScore;
			flag = true;
			count++;
			newNode = newNode->Pre;
		}
		else
		{	/* 总分相同,则排名相同 */
			if (newNode->sumScore == preScore)
			{
				newNode->rank = preRank;
				count++;
				newNode = newNode->Pre;
			}
			/* 总分更低,则排名根据前面的人数更新 */
			else if (newNode->sumScore < preScore)
			{
				newNode->rank = ++count;
				preScore = newNode->sumScore;
				newNode = newNode->Pre;
			}
		}
	}

}
/* 根据解决问题数量再排序一次 */
void nSolveSort(int N, int K, bucket userArray[], bucket problemSolveArray[])
{
	/* k + 1个桶: 0到K */
	/* 基数:K + 1 */
	int i;
	int count = 0;
	bool flag = false;	/* flag为false表示此时为第一次排序 */
	userInfo* newNode = userArray[0].First;
	userInfo* nextNode;
	for (i = 0; i < 10; ) //i代表分数桶的数量
	{		
		/* 跳到下一个非空桶 */
		while (flag == true && newNode == NULL)
		{
			newNode = userArray[++i].First;
		}
		/* 找到第一个节点 */
		while (flag == false && newNode == NULL)
		{
			newNode = userArray[++i].First;
		}
		nextNode = newNode->Next;
		newNode->Pre = NULL;
		newNode->Next = NULL;
		flag = true;
		/* 根据解决问题数将其放到对应桶 */
		int numSolve = newNode->nSolve;
		/* 目标桶为空 */
		if (problemSolveArray[numSolve].First == NULL)
		{
			problemSolveArray[numSolve].First = newNode;
			problemSolveArray[numSolve].Last = newNode;
		}
		/* 目标桶仅有一个元素 */
		else if (problemSolveArray[numSolve].First != NULL && problemSolveArray[numSolve].First == problemSolveArray[numSolve].Last)
		{
			problemSolveArray[numSolve].First->Next = newNode;
			newNode->Pre = problemSolveArray[numSolve].First;
			problemSolveArray[numSolve].Last = newNode;
		}
		/* 目标桶不止一个元素 */
		else
		{
			problemSolveArray[numSolve].Last->Next = newNode;
			newNode->Pre = problemSolveArray[numSolve].Last;
			problemSolveArray[numSolve].Last = newNode;
		}
		newNode = nextNode;
	}
}

void printUserInfo(int K, int P[], userInfo* curUser)
{
	int i;
	std::cout << curUser->rank;
	std::cout << ' ' << curUser->user_id;
	for (i = 0; i < K; i++)
	{
		if (curUser->score[i] == -1)
			std::cout << ' ' << '-';
		else
			std::cout << ' ' << curUser->score[i];
	}
}
/* 输出最终信息 */
void output(int N, int K, int P[], bucket problemSolveArray[])
{
	int count = 0;
	int i = MAX_PROBLEM;
	bool flag = false;
	userInfo* curNode = problemSolveArray[i].First;
	while (count <= N && i >= 0)
	{	
		/* 跳到下一个非空桶末尾 */
		while (flag == true && curNode == NULL)
		{
			curNode = problemSolveArray[++i].Last;
		}
		/* 找到第一个输出的节点 */
		while (flag == false && curNode == NULL)
		{
			curNode = problemSolveArray[--i].Last;
		}
		flag = true;
		printUserInfo(K, P, curNode);
		count++;
		curNode = curNode->Pre;
	}
}
/* 根据用户ID再排一次序 */
void idSort(int N, int K, bucket problemSolveArray[])
{
	/* 用户ID */
}
int main()
{
	int N, K, M;	/* N:用户总数 K:问题总数 M:提交总数*/
	int P[MAX_PROBLEM];
	userInfo user[MAX_USERS];	/* 存储用户信息 */
	bucket scoreArray[10];
	bucket problemSolveArray[MAX_PROBLEM + 1];
	/* 初始化-读取输入 */
	std::cin >> N >> K >> M;
	for (int i = 1; i <= K; i++)
		std::cin >> P[i];
	/* 统计用户信息 */
	getUserInfo(N, K, M, P, user);
	/* 按照分数进行基数排序 */
	scoreSort(N, K, P, user, scoreArray);
	/* 获取排名 */
	getRank(N, scoreArray);
	/* 根据解决问题数量再排序一次 */
	nSolveSort(N, K, scoreArray, problemSolveArray);
	/* 输出 */
	output(N, K, P, problemSolveArray);

	return 0;
}
相关推荐
淀粉肠kk1 小时前
【数据结构】二叉树(2)
数据结构·算法
予安灵1 小时前
图的邻接矩阵和邻接表存储
数据结构·算法·
kitesxian2 小时前
Leetcode207. 课程表(HOT100)
数据结构
明月*清风2 小时前
【数据结构专栏】二叉搜索树(Binary Search Tree)的剖析?
开发语言·数据结构·c++·visualstudio
Beau_Will2 小时前
数据结构-树状数组专题(2)
数据结构·c++·算法
~yY…s<#>3 小时前
【刷题21】BFS解决FloodFill算法专题
数据结构·c++·算法·leetcode·宽度优先
sid_Tang3 小时前
算法的空间复杂度
数据结构
edward13463 小时前
[JLOI2014] 松鼠的新家(重链剖分+线段树)
数据结构·c++·算法
2401_858286114 小时前
L13.【LeetCode笔记】合并两个有序数组
c语言·开发语言·数据结构·笔记·算法·leetcode
苏言の狗6 小时前
CCF认证202406-01 | 矩阵重塑(其一)
c语言·数据结构·c++·算法·矩阵