三道排序题

P1177 【模板】排序

题目描述

原题点这里-->P1177 【模板】排序 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

将读入的 �N 个数从小到大排序后输出。

输入格式

第一行为一个正整数 N。

第二行包含 N 个空格隔开的正整数 ai​,为你需要进行排序的数。

输出格式

将给定的 N 个数从小到大输出,数之间空格隔开,行末换行且无空格。

输入输出样例

输入 #1

5
4 2 4 5 1

输出 #1

1 2 4 4 5

说明/提示

对于 20%20% 的数据,有 1≤N≤1000;

对于 100%100% 的数据,有 1≤N≤100000,1≤ai​≤1000000000。

解题过程 

这道题需要时间复杂度为O(nlogn)的排序算法,这里我用的是快速排序。

源代码

#include<stdio.h>

int a[100010];

void swap(int *a,int *b)//交换两个数的位置 
{
	int t=*a;
	*a=*b;
	*b=t;
}

//快速排序 
void q(int l,int r)
{
	if(l>=r)
		return;
	int mid=l-1;
	int tr=r+1;
	int tl=l-1;
	int v=a[(l+r)/2];

	int i=1;
	while(mid<tr-1)
	{
		if(a[mid+1]<v)
		{
			if(mid==tl)
			{
				mid++;
				tl++;
			}
			else
			{
				swap(&a[++tl],&a[++mid]);
			}
			
		}
		else if(a[mid+1]==v)
		{
			mid++;
		}
		else
		{
			swap(&a[mid+1],&a[--tr]);

		}
	}
	q(l,tl);
	q(tr,r);
		
}

int main()
{
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		scanf("%d",&a[i]);
	}
	
	q(0,n-1);
	
	for(int i=0;i<n-1;i++)
	{
		printf("%d ",a[i]);
	}
	printf("%d\n",a[n-1]);
	return 0;
}

P1068 [NOIP2009 普及组] 分数线划定

题目描述

原题点这里-->P1068 [NOIP2009 普及组] 分数线划定 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

世博会志愿者的选拔工作正在 A 市如火如荼的进行。为了选拔最合适的人才,A 市对所有报名的选手进行了笔试,笔试分数达到面试分数线的选手方可进入面试。面试分数线根据计划录取人数的 150% 划定,即如果计划录取 m 名志愿者,则面试分数线为排名第 m×150%(向下取整)名的选手的分数,而最终进入面试的选手为笔试成绩不低于面试分数线的所有选手。

现在就请你编写程序划定面试分数线,并输出所有进入面试的选手的报名号和笔试成绩。

输入格式

第一行,两个整数 n,m(5≤n≤5000,3≤m≤n),中间用一个空格隔开,其中 n 表示报名参加笔试的选手总数,m 表示计划录取的志愿者人数。输入数据保证m×150% 向下取整后小于等于 n。

第二行到第 n+1 行,每行包括两个整数,中间用一个空格隔开,分别是选手的报名号 k(1000≤k≤9999)和该选手的笔试成绩 s(1≤s≤100)。数据保证选手的报名号各不相同。

输出格式

第一行,有 22 个整数,用一个空格隔开,第一个整数表示面试分数线;第二个整数为进入面试的选手的实际人数。

从第二行开始,每行包含 22 个整数,中间用一个空格隔开,分别表示进入面试的选手的报名号和笔试成绩,按照笔试成绩从高到低输出,如果成绩相同,则按报名号由小到大的顺序输出。

输入输出样例

输入 #1

6 3 
1000 90 
3239 88 
2390 95 
7231 84 
1005 95 
1001 88

输出 #1

88 5 
1005 95 
2390 95 
1000 90 
1001 88 
3239 88 

说明/提示

【样例说明】

m×150%=3×150%=4.5,向下取整后为 44。保证 44 个人进入面试的分数线为 8888,但因为 8888 有重分,所以所有成绩大于等于 8888 的选手都可以进入面试,故最终有 55 个人进入面试。

解题过程 

因为当成绩相同时需要按报名号由小到大的顺序输出,所以在对成绩进行从大到小的排序时,还需要对成绩相同的选手的报名号进行从小到大的排序。

源代码

#include<stdio.h>
typedef struct{
	int num;
	int grade;
}P;

P p[5010];

void swap(P *a,P *b)
{
	P t=*a;
	*a=*b;
	*b=t;
}

//根据成绩相同选手的报名号进行从小到大排序
void q1(int l,int r)
{
	if(l>=r)
		return;
	int mid=l-1;
	int tr=r+1;
	int tl=l-1;
	int v=p[(l+r)/2].num;

	int i=1;
	while(mid<tr-1)
	{
		if(p[mid+1].num<v)
		{
			if(mid==tl)
			{
				mid++;
				tl++;
			}
			else
			{
				swap(&p[++tl],&p[++mid]);
			}
			
		}
		else if(p[mid+1].num==v)
		{
			mid++;
		}
		else
		{
			swap(&p[mid+1],&p[--tr]);

		}
	}
	q1(l,tl);
	q1(tr,r);	
}

void q(int l,int r)
{
	if(l>=r)
		return;
	int mid=l-1;
	int tr=r+1;
	int tl=l-1;
	int v=p[(l+r)/2].grade;

	int i=1;
	while(mid<tr-1)
	{
		if(p[mid+1].grade>v)
		{
			if(mid==tl)
			{
				mid++;
				tl++;
			}
			else
			{
				swap(&p[++tl],&p[++mid]);
			}
			
		}
		else if(p[mid+1].grade==v)
		{
			mid++;
		}
		else
		{
			swap(&p[mid+1],&p[--tr]);

		}
	}
	q(l,tl);
	q(tr,r);
	//根据成绩相同选手的报名号进行从小到大排序 
	q1(tl+1,tr-1);	
}

int main()
{
	int m,n;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&p[i].num,&p[i].grade);
	}
	q(1,n);
	
	//计算分数线 
	int k=m*3/2;
	int k1=p[k].grade;
	 
	//计算通过人数 
	int k2;
	for(k2=k+1;p[k2].grade==k1;k2++);
	
	printf("%d %d\n",k1,k2-1);
	for(int i=1;i<=k2-1;i++)
	{
		printf("%d %d\n",p[i].num,p[i].grade);
	}

	
	return 0;
}

P1059 [NOIP2006 普及组] 明明的随机数

题目描述

原题点这里-->P1059 [NOIP2006 普及组] 明明的随机数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了 N 个 11 到 1000 之间的随机整数 (N≤100),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作。

输入格式

输入有两行,第 1 行为 1 个正整数,表示所生成的随机数的个数 N。

第 2 行有 N 个用空格隔开的正整数,为所产生的随机数。

输出格式

输出也是两行,第 1 行为 1 个正整数 M,表示不相同的随机数的个数。

第 2 行为 M 个用空格隔开的正整数,为从小到大排好序的不相同的随机数。

输入输出样例

输入 #1

10
20 40 32 67 40 20 89 300 400 15

输出 #1

8
15 20 32 40 67 89 300 400

说明/提示

NOIP 2006 普及组 第一题

解题过程 

这题可以先对随机数进行快排,然后遍历排序后的随机数统计出不同随机数的个数,但由于输出所有不同随机数时也需要一个循环遍历,所以我们考虑在快排的过程中统计重复随机数的个数。

源代码

#include<stdio.h>

int a[10010];
int b[1010];
int ans;//用来统计重复随机数的个数 

void swap(int *a,int *b)
{
	int t=*a;
	*a=*b;
	*b=t;
}

void q(int l,int r)
{
	if(l>=r)
		return;
	int mid=l-1;
	int tr=r+1;
	int tl=l-1;
	int v=a[(l+r)/2];

	int i=1;
	while(mid<tr-1)
	{
		if(a[mid+1]<v)
		{
			if(mid==tl)
			{
				mid++;
				tl++;
			}
			else
			{
				swap(&a[++tl],&a[++mid]);
			}
		}
		else if(a[mid+1]==v)
		{
			mid++;
		}
		else
		{
			swap(&a[mid+1],&a[--tr]);
		}
	}
	if(tr-tl>2)//有重复随机数出现时tr-tl>2 
		ans+=tr-tl-2;
	q(l,tl);
	q(tr,r);
		
}

int main()
{
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		scanf("%d",&a[i]);
	}
	
	q(0,n-1);
	
	ans=n-ans;//得出不同随机数的个数 
	printf("%d\n",ans);
	for(int i=0;i<n;i++)
	{
		if(!b[a[i]])
		{
			printf("%d ",a[i]);
			b[a[i]]=1;
		}
		
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值