算法竞赛入门经典 例题4-6

UVa12412

A Typical Homework (a.k.a Shi Xiong Bang Bang Mang)

这是一道无脑大作业。

有几点注意一下:

  • 有任意位置添加和删除操作,所以用了list而不是vector
  • 关于query的排名,为了简单,我在插入的时候就按照总分排名了,但是没有计算名次。但是同名的人要根据它们加入的顺序打印,而不是根据排名(排名相同再考虑加入顺序)打印,所以我又弄了一个全局变量iOrder来表示加入顺序。这样在查询的时候更新一下排名,把需要输出的人在弄到一个vecTmp中,按照iOrder字段重新排名
  • 平均分计算的时候加上一个EPS = 1e-5可以消除浮点数误差,不消除的话在UVa上就会WA掉

排名要计算并列这个功能之前没搞过,后来想了这么一个方法。在从高到低遍历总分的过程中,维护三个变量,一个rank表示名次,一个idx表示总人数,还有一个sum表示当前总分。如果当前学生的总分等于sum,那么是并列的情况,rank不变,sum也不变,否则就往下排,rank=idxsum更新为当前学生的分数(因为如果有1个第1和2个并列第2的话那么下一个人应该是第4名,英文题目中也强调了)。

#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <algorithm>
#include <iomanip>

#define CLASSES 21
#define COURSES 4
#define CHINESE 0
#define MATH 1
#define ENGLISH 2
#define PROGRAMMING 3
#define OVERALL_TYPE 5
#define PASSED_SCORE 60
#define PASSED_ALL 0
#define PASSED_3 1
#define PASSED_2 2
#define PASSED_1 3
#define FAILED_ALL 4

#define EPS 1e-5

using namespace std;

typedef struct Info
{
	string strSID;
	string strName;
	int iCID;
	int iScore[COURSES];
	int iSum;
	int iRank;
	int iOrder;
}Info;

list<Info> lstInfo;
int iOrder = 0;

const vector<string> vecstrClass = { "Chinese", "Mathematics", "English", "Programming" };

int selMenu()
{
	cout << "Welcome to Student Performance Management System (SPMS).\n\n";
	cout << "1 - Add\n";
	cout << "2 - Remove\n";
	cout << "3 - Query\n";
	cout << "4 - Show ranking\n";
	cout << "5 - Show Statistics\n";
	cout << "0 - Exit\n";
	cout << endl;
	int iSel;
	cin >> iSel;
	return iSel;
}

bool checkQuit(const string &strInput)
{
	if (strInput.size() == 1 && strInput[0] == '0') return true;
	else return false;
}

bool checkDup(const string &strSID)
{
	for (auto iter = lstInfo.begin(); iter != lstInfo.end(); iter++)
	{
		if (iter->strSID == strSID){
			return true;
		}
	}
	return false;
}

void insertInfo(const Info &info)
{
	for (auto iter = lstInfo.begin(); iter != lstInfo.end(); iter++)
	{
		if (iter->iSum < info.iSum){
			lstInfo.insert(iter, info);
			return;
		}
	}
	lstInfo.push_back(info);
	return;
}

void add()
{
	while (1){
		cout << "Please enter the SID, CID, name and four scores. Enter 0 to finish.\n";
		Info info;
		cin >> info.strSID;
		if (checkQuit(info.strSID)) return;
		cin >> info.iCID;
		cin.get();
		cin >> info.strName;
		info.iSum = 0;
		for (int i = 0; i < sizeof(info.iScore) / sizeof(int); i++)
		{
			cin >> info.iScore[i];
			info.iSum += info.iScore[i];
		}
		if (checkDup(info.strSID)){
			cout << "Duplicated SID.\n";
			continue;
		}
		info.iOrder = iOrder++;
		insertInfo(info);
	}
}

void remove()
{
	string strInput;
	while (1){
		cout << "Please enter SID or name. Enter 0 to finish.\n";
		cin >> strInput;
		if (checkQuit(strInput)) return;
		int cnt = 0;
		for (auto iter = lstInfo.begin(); iter != lstInfo.end();)
		{
			if (iter->strSID == strInput || iter->strName == strInput){
				iter = lstInfo.erase(iter);
				cnt++;
			}
			else iter++;
		}
		cout << cnt << " student(s) removed.\n";
	}
}

void printRank(const Info &info)
{
	cout << info.iRank << ' ' << info.strSID << ' ' << info.iCID << ' '
		<< info.strName << ' ';
	for (int i = 0; i < COURSES; i++)
	{
		cout << info.iScore[i] << ' ';
	}
	cout << info.iSum << ' ';
	double dAvg = ((double)info.iSum) / COURSES + EPS;
	cout << setprecision(2) << fixed << dAvg + EPS << endl;
}

void query()
{
	string strInput;
	while (1){
		cout << "Please enter SID or name. Enter 0 to finish.\n";
		cin >> strInput;
		if (checkQuit(strInput)) return;
		size_t idx = 1, rank = 0;
		int sum = 401;
		vector<Info> vecTmp;
		for (auto iter = lstInfo.begin(); iter != lstInfo.end(); iter++, idx++)
		{
			if (iter->iSum != sum){
				rank = idx;
				sum = iter->iSum;
			}
			iter->iRank = rank;
			if (iter->strSID == strInput || iter->strName == strInput){
				vecTmp.push_back(*iter);
			}
		}
		sort(vecTmp.begin(), vecTmp.end(),
			[](const Info &i1, const Info &i2)->bool{return i1.iOrder < i2.iOrder; });
		for_each(vecTmp.begin(), vecTmp.end(), printRank);
	}
}

void showRank()
{
	cout << "Showing the ranklist hurts students' self-esteem. Don't do that.\n";
	return;
}

void showStatistic()
{
	int iCID;
	cout << "Please enter class ID, 0 for the whole statistics.\n";
	cin >> iCID;
	//二维数组表示每个班级该课程的统计数据
	//第一维取0表示所有班级
	vector<vector<int>> vviSum(CLASSES, vector<int>(COURSES, 0));
	vector<vector<int>> vviPassed(CLASSES, vector<int>(COURSES, 0));
	vector<vector<int>> vviFailed(CLASSES, vector<int>(COURSES, 0));
	vector<vector<int>> vviOverall(CLASSES, vector<int>(OVERALL_TYPE, 0));
	vector<int> viTotalStudent(CLASSES, 0);
	for (auto iter = lstInfo.begin(); iter != lstInfo.end(); iter++)
	{
		//更新学生总数
		viTotalStudent[0]++;
		viTotalStudent[iter->iCID]++;
		int iPassedCnt = 0;
		for (int course = CHINESE; course <= PROGRAMMING; course++)
		{
			//更新该课程总成绩
			vviSum[0][course] += iter->iScore[course];
			vviSum[iter->iCID][course] += iter->iScore[course];
			//更新及格情况
			if (iter->iScore[course] >= PASSED_SCORE){
				vviPassed[0][course]++;
				vviPassed[iter->iCID][course]++;
				iPassedCnt++ ;
			}
			else{
				vviFailed[0][course]++;
				vviFailed[iter->iCID][course]++;
			}
		}
		//更新通过情况
		switch (iPassedCnt)
		{
		case 4:
			vviOverall[0][PASSED_ALL]++;
			vviOverall[iter->iCID][PASSED_ALL]++;
		case 3:
			vviOverall[0][PASSED_3]++;
			vviOverall[iter->iCID][PASSED_3]++;
		case 2:
			vviOverall[0][PASSED_2]++;
			vviOverall[iter->iCID][PASSED_2]++;
		case 1:
			vviOverall[0][PASSED_1]++;
			vviOverall[iter->iCID][PASSED_1]++;
			break;
		case 0:
			vviOverall[0][FAILED_ALL]++;
			vviOverall[iter->iCID][FAILED_ALL]++;
			break;
		}
	}
	double dAvg = 0.0;
	for (int i = 0; i < COURSES; i++)
	{
		cout << vecstrClass[i] << endl;
		if (viTotalStudent[iCID] == 0) cout << "Average Score: -nan" << endl;
		else cout << "Average Score: " << setprecision(2) << fixed << ((double)vviSum[iCID][i]) / viTotalStudent[iCID] + EPS << endl;
		cout << "Number of passed students: " << vviPassed[iCID][i] << endl;
		cout << "Number of failed students: " << vviFailed[iCID][i] << endl;
		cout << endl;
	}
	cout << "Overall:\n";
	cout << "Number of students who passed all subjects: " << vviOverall[iCID][PASSED_ALL] << endl;
	cout << "Number of students who passed 3 or more subjects: " << vviOverall[iCID][PASSED_3] << endl;
	cout << "Number of students who passed 2 or more subjects: " << vviOverall[iCID][PASSED_2] << endl;
	cout << "Number of students who passed 1 or more subjects: " << vviOverall[iCID][PASSED_1] << endl;
	cout << "Number of students who failed all subjects: " << vviOverall[iCID][FAILED_ALL] << endl;
	cout << endl;
}

int main()
{
	int iSel = 0;
	while (1){
		iSel = selMenu();
		if (iSel == 0) break;
		switch (iSel)
		{
		case 1:
			add();
			break;
		case 2:
			remove();
			break;
		case 3:
			query();
			break;
		case 4:
			showRank();
			break;
		case 5:
			showStatistic();
			break;
		}
	}
	return 0;
}
/*
1
0011223344 1 John 79 98 91 100
0022334455 1 Tom 59 72 60 81
0011223344 2 Alice 100 100 100 100
2423475629 2 John 60 80 30 99
0
3
0022334455
John
0
5
1
2
0011223344
0
5
0
4
0
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值