算法笔记-排序

算法笔记-排序


A1025
题意:n个考点,k个测试人员,给了学号,和成绩,求考点的排名,和总排名,并按照总排名作为一级输出,学号排名作为二级输出。
思路:结构体存储学生的信息,然后,输入完一个考点的信息,排一次序,如果和前面的成绩相同,则排名相同,如果不同则为下标加一,最后所有的都输入完了,再进行最终排序。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

struct STD{
	char num[20];//放学号
	int res;//成绩
	int lr;//考点排名
	int fr;//最终排名
	int ln;//考场号
}stdu[30100];

bool cmp(STD a,STD b){
	if(a.res!=b.res)return a.res>b.res;//成绩不同成绩高的在前面
	else{//成绩相同学号小的在前面
		return strcmp(a.num,b.num)<0;
	}
}


int main(){
	int n,k;//n个考点,每个考点k个考生
	scanf("%d",&n);
	int count=0;//记录总人数,方便找到每输入一个结点的范围
	for(int i=1;i<=n;i++){
		scanf("%d",&k);
		for(int j=0;j<k;j++){
			scanf("%s %d",stdu[count].num,&stdu[count].res);			
			getchar();
			stdu[count].ln=i;
			count++;
		}
		sort(stdu+count-k,stdu+count,cmp);//sort是左闭右开区间
		stdu[count-k].lr=1;
		for(int j=count-k+1;j<count;j++){
			if(stdu[j].res==stdu[j-1].res)stdu[j].lr=stdu[j-1].lr;
			else stdu[j].lr=j-(count-k)+1;
		}
	}
	sort(stdu,stdu+count,cmp);
	stdu[0].fr=1;
	for(int i=1;i<count;i++){
		if(stdu[i].res==stdu[i-1].res)stdu[i].fr=stdu[i-1].fr;
		else stdu[i].fr=i+1;
	}
	printf("%d\n",count);
	for(int i=0;i<count;i++){
		printf("%s %d %d %d\n",stdu[i].num,stdu[i].fr,stdu[i].ln,stdu[i].lr);
	}
	system("pause");
	return 0;
}


A1062
题意:n个人,l是最低线,必须两个都达标,h是优秀线,两个都超过,是第一类,根据分数排,第二类是,德高与H,但是能力不足,第三类是两个都不足,但是德高,第四类是其他,但合格,第五类是不合格。
思路:我本来想先把每个人拆分成五个vector,然后再进行排序,发现不是最好的办法,但是,答案和我差不多,答案没有给他们分成五个vector,只用了一个tag就解决了,给每个人分了组,分组号小的在前面,分组的方式,因为是if-else结构,如果有最麻烦的就把最麻烦的放在最后有else,其他的平均分。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

struct STD{
	char id[10];//学号
	int tag,vir,tal,sum;//tag标记他是那个类的
}stdu[100100];

int Charge(STD a,int H,int L){
	if(a.vir<L||a.tal<L)return 5;
	else if(a.vir>=H&&a.tal>=H)return 1;
	else if(a.vir>=H&&a.tal<H)return 2;
	else if(a.vir>=a.tal)return 3;
	else return 4;
}

bool cmp(STD a,STD b){
	if(a.tag!=b.tag)return a.tag<b.tag;//小的在前面
	else if(a.sum!=b.sum)return a.sum>b.sum;
	else if(a.vir!=b.vir)return a.vir>b.vir;
	else return strcmp(a.id,b.id)<0;//大的在前面,这个变了
}

int main(){
	int n,H,L;
	scanf("%d%d%d",&n,&L,&H);
	int count=0;
	for(int i=0;i<n;i++){
		scanf("%s%d%d",stdu[i].id,&stdu[i].vir,&stdu[i].tal);
		stdu[i].sum=stdu[i].vir+stdu[i].tal;
		stdu[i].tag=Charge(stdu[i],H,L);
		if(stdu[i].tag!=5)count++;
	}
	sort(stdu,stdu+n,cmp);
	printf("%d\n",count);
	for(int i=0;i<count;i++){
		printf("%s %d %d\n",stdu[i].id,stdu[i].vir,stdu[i].tal);
	}
	system("pause");
	return 0;
}

A1012
题意:CME三科,再加一个平均数,N个人M个查成绩的,输入六位ID,然后是三个整数分别表示CME。求他们的最好的排名,和该科的代号,给了ACME这样的优先级,如果分数相同就按优先级高的先排名。
思路:这个成绩排序,只输出内部排名(就是对应上一个科目的考点排名),不输出外部排名,上一个是每一个考点输入完了,排一遍。这个只能等所有的都输入完了,排三遍,然后给到他们的单科排名,然后遍历一遍输出他们的最好排名,能不能给排名的时候判断一下然后更新的呢,也可以尝试,但是这里注意排名四次就得是四个排名函数,所以重复率太高,所以就得让他们跟数字建立起联系,这样的话就可以只写一个cmp就行了,所以就是吧他们的成绩都放进一个数组里,然后拍第几个就把第几个成绩送过去排序,因为存储完了,要输入学号查找数值,所以要用哈希表,如果直接都存到结构体里面去,那么没来一个人都要输出一遍
注意:

  • for循环改变了增加的量,所有的都要变,不能只改变一个
  • sort函数的变量传递,可以放在外面
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;

struct STD{
	int name;
	int grad[5];//0123,3个代号表示排的是第几组的成绩
	int R[5];//每个的排名
}stdu[5000];

int RK[1000100][4]={0};//因为后来要输入学号查找数值,所以用哈希表,赋值为零的原因是可以判断是否出现过

int now;//now放不了cmp的里面,但是可以放在外面啊,一样可以传递啊
bool cmp1(STD a,STD b){//为了排单科成绩
	return a.grad[now]>b.grad[now];//成绩高的放在前面
}

char T[4]={'A','C','M','E'};

void Rank(STD stdu[],int len,int i){
	stdu[0].R[i]=1;
	RK[stdu[0].name][i]=stdu[0].R[i];
	for(int j=1;j<len;j++){
		if(stdu[j].grad[i]==stdu[j-1].grad[i]){
			stdu[j].R[i]=stdu[j-1].R[i];
		}
		else {
			stdu[j].R[i]=j+1;
		}
		RK[stdu[j].name][i]=stdu[j].R[i];
	}
}

double round(double r)
{
	return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5);
}

int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++){
		scanf("%d %d %d %d",&stdu[i].name,&stdu[i].grad[1],&stdu[i].grad[2],&stdu[i].grad[3]);
		stdu[i].grad[0]= round((stdu[i].grad[1]+stdu[i].grad[2]+stdu[i].grad[3])/3.0)+0.5;
	}
	for(now=0;now<4;now++){
		sort(stdu,stdu+n,cmp1); 
		Rank(stdu,n,now);
	}
	for(int i=0;i<m;i++){//判断输出
		int cn;//查询学号
		scanf("%d",&cn);
		if(RK[cn][0]==0)printf("N/A\n");
		else{
			char bt='A';//最好的课程
			int br=RK[cn][0];//最好的排名
			for(int j=0;j<4;j++){
				if(br>RK[cn][j]){
					br=RK[cn][j];
					bt=T[j];
				}
			}
			printf("%d %c\n",br,bt);
		}
	}
	return 0;
}

A1016
题意:24个小时,每个小时的费用不一样,给了不同的通话记录,先找到有效的通话记录然后,输出每个人的账单
思路:先进行排序,按照时间排序,找到相邻的online和offline,才是有效的记录,然后遍历计时间,算费用,当换了姓名以后输出总费用,计费是这个题的核心,采用跳动计时间法,但应注意,一天是24小时,不是60个小时,然后,每当60转0的时候,是不跳动时间的,所以当时所有的时间计数都要减一,然后是,当这种变量多的时候,每个变量每次循环之前都要赋初值,所以定义变量的时候,就要写进去,要不然,很容易忘了,就算不忘,也不知道加在哪里。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
using namespace std;

struct NODE{
	string name;
	int t[5];
	int tag;//1表示online,0表示offline
}node[1010];

int charg[25];//记录每个小时的资费

bool cmp(NODE a,NODE b){
	if(a.name!=b.name)return a.name<b.name;
	for(int i=0;i<4;i++){
		if(a.t[i]!=b.t[i])return a.t[i]<b.t[i];
	}
}

int main(){
	for(int i=0;i<24;i++){//输入资费
		scanf("%d",&charg[i]);
	}
	int n;//n条记录
	scanf("%d",&n);
	getchar();
	for(int i=0;i<n;i++){//输入数据
		string t;
		cin>>node[i].name;
		scanf("%d:%d:%d:%d",&node[i].t[0],&node[i].t[1],&node[i].t[2],&node[i].t[3]);
		cin>>t;
		if(t=="on-line")node[i].tag=1;
		else node[i].tag=0;
	}
	sort(node,node+n,cmp);//排序
	int needprint=0;
	float lc=0,alc=0;//lc是每条的计费,alc是总计费
	int c1=0,c2=0;//c1计费用,c2输出时常用
	for(int i=0;i<n;i++){//遍历,找合格的,计费
		if(node[i].name==node[i+1].name){//名字一样,继续找,找到了一个needprint加一,然后,总费用加一
			if(node[i].tag==1&&node[i+1].tag==0){//前后连续的on,off,说明是有效的
				int d,h,m;
				for(d=node[i].t[1],h=node[i].t[2],m=node[i].t[3],c1=0,c2=0,lc=0;
					d!=node[i+1].t[1]|| h!=node[i+1].t[2]|| m!=node[i+1].t[3];
					m++,c1++,c2++){						
						if(m==60){//每到了新的一小时,要计费了
							lc+=(c1*charg[h])/100.0;
							c1=-1;
							m=-1;
							h++;
							c2--;
						}
						if(h==24){
							h=0;
							d++;
						}
				}
				if(c1!=0){//说明还有一些分钟没有计费
					lc+=(c1*charg[h])/100.0;
				}
				needprint++;
				if(needprint==1){
					cout<<node[i].name<<" ";
					printf("%02d\n",node[i].t[0]);
				}
				alc+=lc;//相邻两条记录判断完了
				printf("%02d:%02d:%02d %02d:%02d:%02d %d $%.2f\n",node[i].t[1],node[i].t[2],node[i].t[3],node[i+1].t[1],node[i+1].t[2],node[i+1].t[3],c2,lc);
			}
		}
		else{//名字不一样,该换人了,如果上一个人有有效记录的话,就输出计费
			if(needprint>0){
				printf("Total amount: $%.2f\n",alc);
				alc=0;
				needprint=0;
			}
		}
	}
	return 0;
}

A1028
题意:excel表格排序功能再现。
思路:switch-case走起即可

#include<cstdio>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;

struct STD{
	int ID;
	string name;
	int grade;
}stdu[100100];

bool cmp1(STD a,STD b){
	return a.ID<b.ID;
}

bool cmp2(STD a,STD b){
	if(a.name!=b.name)return a.name<b.name;
	else return a.ID<b.ID;
}

bool cmp3(STD a,STD b){
	if(a.grade!=b.grade)return a.grade<b.grade;
	else return a.ID<b.ID;
}

int main(){
	int n,c;
	scanf("%d%d",&n,&c);
	for(int i=0;i<n;i++){
		scanf("%d",&stdu[i].ID);
		cin>>stdu[i].name;
		scanf("%d",&stdu[i].grade);
	}
	switch (c){
		case 1:sort(stdu,stdu+n,cmp1);break;
		case 2:sort(stdu,stdu+n,cmp2);break;
		case 3:sort(stdu,stdu+n,cmp3);break;
	}
	for(int i=0;i<n;i++){
		printf("%06d ",stdu[i].ID);
		cout<<stdu[i].name<<" ";
		printf("%d\n",stdu[i].grade);
	}
	return 0;
}

A1055
题意:给了一堆数据,然后,挑选出符合年龄区间的m个最富有的人
思路:这里既要考虑年龄,又得考虑钱财,两个都要满足条件才可以,我想到的办法,肯定是,先输入进去,一个数组进行存放着,然后遍历,看是否满足区间,按财富排列下标。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<vector>
#include<cstring>
using namespace std;

struct MAN{
	string name;
	int age;
	int w;//钱
}man[100100],valid[100100];//此处的分号别忘了打,否则后面就都错了
//在各个年龄段都是前一百名的先挑出来,然后再整别的,要不然会超时
int AGE[210]={0};

bool cmp(MAN a,MAN b){
	if(a.w!=b.w) return a.w>b.w;
	else if(a.age!=b.age)return a.age<b.age;
	else return a.name<b.name;
}


int main(){
	int n,k;
	scanf("%d%d",&n,&k);
	for(int i=0;i<n;i++){
		cin>>man[i].name;
		scanf("%d%d",&man[i].age,&man[i].w);
	}
	sort(man,man+n,cmp);
	int validnum=0;//存放到valid数组中的人数
	for(int i=0;i<n;i++){
		if(AGE[man[i].age]<=100){//用年龄数组来计数,看看是不是到了100个人
			AGE[man[i].age]++;
			valid[validnum++]=man[i];
		}
	}
	int m,l,r;//m是指的前几名,lr为左右边界
	for(int i=1;i<=k;i++){//输出函数
		scanf("%d %d %d",&m,&l,&r);
		printf("Case #%d:\n",i);
		int count=0;//count是记录输出了几个人用的
		for(int j=0;j<validnum&&count<m;j++){
			if(valid[j].age>=l&&valid[j].age<=r){
				cout<<valid[j].name<<" ";
				printf("%d %d\n",valid[j].age,valid[j].w);
				count++;
			}
		}
		if(count==0)printf("None\n");
	}
	system("pause");
	return 0;
}

A1075
题意:N个人,K个问题,M次提交,每题分值,五位数的ID,题号,得分顺次给出,输出排名,学号,成绩,注意如果没有提交则用-表示,如果提交了没通过编译,分数是0分,但是输入的时候用-1表示
思路:每个人一个成绩数组,先初始化为-1,然后输入,当输入的是-1的时候,变为0,每输入一个和标准成绩比对,看看如果是满分,就把满分记录加1,最前面放总成绩,最后面放满分记录。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<iostream>
#include<vector>
using namespace std;

struct STD{
	int ID,total,tag;
	int grade[6];
	int v;//表示是否编译成功
}stdu[10010];

bool cmp(STD a,STD b){
	if(a.total!=b.total)return a.total>b.total;//总成绩高的在前面
	else if(a.tag!=b.tag)return a.tag>b.tag;//满分次数多的在前面
	else return a.ID<b.ID;
}

int p[7];//放每个题的分值


int main(){
	int n,k,m;//n个人,k个问题,m个提交
	scanf("%d%d%d",&n,&k,&m);
	for(int i=1;i<=k;i++){
		scanf("%d",&p[i]);
	}
	for(int i=1;i<=n;i++){//先赋初值
		stdu[i].ID=i;
		stdu[i].tag=stdu[i].total=stdu[i].v=0;
		memset(stdu[i].grade,-1,sizeof(stdu[i].grade));
	}
	for(int i=0;i<m;i++){
		int id,pro,g;
		scanf("%d%d%d",&id,&pro,&g);
		if(g==-1&&g>=stdu[id].grade[pro]){
			if(stdu[id].grade[pro]==-1)stdu[id].grade[pro]=0;//说明是第一次输入
			stdu[id].total+=g-stdu[id].grade[pro];//上述三种情况都需要更新数组,所以,一起整。
			stdu[id].grade[pro]=g;
		}
		if(g>stdu[id].grade[pro]){//只有新来的数>=原来里面的数,才会更新
			if(g==-1)g=0;//如果是-1,表明编译没成功,让他的分数变成0,方便后面
			if(g==p[pro]){//如果是满分,说明是有效输入,标签变成1,满分标签自加
				stdu[id].tag++;
				stdu[id].v=1;
			}
			else stdu[id].v=1;//如果在-1和满分之间的数也是有效输入
			if(stdu[id].grade[pro]==-1)stdu[id].grade[pro]=0;//说明是第一次输入
			stdu[id].total+=g-stdu[id].grade[pro];//上述三种情况都需要更新数组,所以,一起整。
			stdu[id].grade[pro]=g;
		}
	}
	sort(stdu+1,stdu+n+1,cmp);//排序,左闭右开区间
	int r=1;
	for(int i=1;i<=n&&stdu[i].v==true;i++){//这种直接输出的不需要赋值,碰到不同的再更新rank
		if(i>1&&stdu[i].total!=stdu[i-1].total){
			r=i;
		}
		printf("%d %05d %d",r,stdu[i].ID,stdu[i].total);
		for(int j=1;j<=k;j++){
			if(stdu[i].grade[j]==-1){
				printf(" -");
			}
			else {
				printf(" %d",stdu[i].grade[j]);
			}
		}
		printf("\n");
	}
	system("pause");
	return 0;
}

A1083
题意:给了记录,然后输出在一个区间的排名情况,n个记录
思路:答案比我简单很多,因为他不单拿出来,只是遍历一遍有就输出,没有就跳过

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

struct STD{
	char name[20];
	char id[20];
	int grade;
}stdu[1000100];

int cmp(int a,int b){
	return stdu[a].grade>stdu[b].grade;
}

int main(){
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%s %s %d",stdu[i].name,stdu[i].id,&stdu[i].grade);
	}
	int grade1,grade2;
	vector<int> res;
	scanf("%d%d",&grade1,&grade2);
	for(int i=0;i<n;i++){
		if(stdu[i].grade>=grade1&&stdu[i].grade<=grade2)
			res.push_back(i);
	}
	if(res.size()==0)printf("NONE");
	else {
		sort(res.begin(),res.end(),cmp);
		for(int i=0;i<res.size();i++){
			printf("%s %s\n",stdu[res[i]].name,stdu[res[i]].id);
		}
	}
	system("pause");
	return 0;
}

A1080
题意:打了一遍然后被删除了,不打了凭记忆吧
思路:先按照排名给他们每个人整一个排名,然后再次循环,内层循环每个人的志愿,检测有没有配额满了,总体比答案的代码优秀一点
心得:

  1. 要一条条的排除问题,最终确定问题的板块,和问题的范围,逐渐缩小,挨个数据试一下。
  2. 如果有一些值,监视没出来,找到他赋值的地方,可能错了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

struct STD{
	int GE,GI;
	int c[7];//第一二三志愿
	int A;
	int rank;
	int num;
}stdu[40100];

int r[40100];//用来放排名

bool cmp(STD a,STD b){
	if(a.A!=b.A)return a.A>b.A;
	else return a.GE>b.GE;
}

int qua[150];
vector<int> res[150];

int main(){
	int n,k,m;
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0;i<m;i++){//m个学校
		scanf("%d",&qua[i]);
	}
	for(int i=0;i<n;i++){//n个人
		scanf("%d%d",&stdu[i].GE,&stdu[i].GI);
		for(int j=0;j<k;j++){
			scanf("%d",&stdu[i].c[j]);
		}
		stdu[i].A=(stdu[i].GE+stdu[i].GI);
		stdu[i].num=i;
	}
	sort(stdu,stdu+n,cmp);
	stdu[0].rank=1;
	r[stdu[0].num]=stdu[0].rank;
	for(int i=1;i<n;i++){//给他们整个排名
		if(stdu[i].A==stdu[i-1].A&&stdu[i].GE==stdu[i-1].GE)
			stdu[i].rank=stdu[i-1].rank;
		else stdu[i].rank=i+1;
		r[stdu[i].num]=stdu[i].rank;
	}
	for(int i=0;i<n;i++){//按排序录取
		for(int j=0;j<k;j++){//k个志愿
			if(qua[stdu[i].c[j]]>0||(stdu[i].rank==r[*(--res[stdu[i].c[j]].end())])){
				qua[stdu[i].c[j]]--;
				res[stdu[i].c[j]].push_back(stdu[i].num);
				break;
			}
		}
	}
	for(int i=0;i<m;i++){//m个学校的录取情况
		if(res[i].size()==0)printf("\n");
		else {
			sort(res[i].begin(),res[i].end());
			printf("%d",res[i][0]);
			for(int j=1;j<res[i].size();j++){//输出该学校的录取情况
				printf(" %d",res[i][j]);
			}
			printf("\n");
		}
	}
	system("pause");
	return 0;
}

A1095

题意:浙江大学有8个校园,很多大门,每个大门都收集了很多的出入数据和穿过校门的车的车牌号。现在给了信息,然后让你求在特定的点,在校园里停车的数量,和在一天的最后,找到停车时间最长的车

每一辆车有两个正数 N104,是记录的数量,K8104,是查询的数量,然后n行数据,每一行是 车牌号 时间 出入 ,车牌是7位数字英文的混合,时间是小时分钟秒,出入是 in out,说明:所有的时间都是在一天以内的,每一个车都有出入的记录,任何的只出不进,只进不出的都不作为有效数据。保证至少有一辆车满足要求,没有同一时间又进又出的车辆时间是用24小时制,k行查询,每一行给了一个时间点并且时间点是从小到大排列的

输出每一条查询的时候,先输出一个此时间点的总数量,然后最后一行输出停车时间最长的车,和对应的时间,如果不是唯一的则按字母序排列。并且在一行内输出

思路:这个题有这样几个问题需要解决
1.每辆车怎么存储:进出时间,车牌号,时间跨度。每辆车一个结构体,然后整一个数组
2.每辆车的时间跨度怎么计算,可以采用循环的方式,一秒秒的跳动,然后所有进来的车辆时间都加一
也可以每一辆车单独去算一下
3.怎么找某个时间点有哪些车,如果每个时间点都是一个散列的话,一天是60*60*24=86400,没有超出可行。
4.所以,整体的思路为:来一辆车,边放时间数组,边记录时间跨度,查询的时候,直接转化为秒数即可。最终时间跨度最长的汽车,可以循环一边输出

在这里插入代码片
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值