7-1 统计工龄 (20 分)
给定公司N名员工的工龄,要求按工龄增序输出每个工龄段有多少员工。
输入格式:
输入首先给出正整数N(≤10
5
),即员工总人数;随后给出N个整数,即每个员工的工龄,范围在[0, 50]。
输出格式:
按工龄的递增顺序输出每个工龄的员工个数,格式为:“工龄:人数”。每项占一行。如果人数为0则不输出该项。
输入样例:
8
10 2 0 5 7 2 5 2
结尾无空行
输出样例:
0:1
2:3
5:2
7:1
10:1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define N 52
int main()
{
int i,n;
scanf("%d",&n);
static int a[N];
int x;
for(i=0;i<n;i++)
{
scanf("%d",&x);
a[x]++;
}
for(i=0;i<=N;i++)
{
if(a[i]!=0)
{
printf("%d:%d\n",i,a[i]);
}
}
return 0;
}
7-2 寻找大富翁 (25 分)
胡润研究院的调查显示,截至2017年底,中国个人资产超过1亿元的高净值人群达15万人。假设给出N个人的个人资产值,请快速找出资产排前M位的大富翁。
输入格式:
输入首先给出两个正整数N(≤10
6
)和M(≤10),其中N为总人数,M为需要找出的大富翁数;接下来一行给出N个人的个人资产值,以百万元为单位,为不超过长整型范围的整数。数字间以空格分隔。
输出格式:
在一行内按非递增顺序输出资产排前M位的大富翁的个人资产值。数字间以空格分隔,但结尾不得有多余空格。
输入样例:
8 3
8 12 7 3 20 9 5 18
结尾无空行
输出样例:
20 18 12
结尾无空行
#include <stdio.h>
int main()
{
long int n,m;
long int i,j,t;
scanf("%ld%ld",&n,&m);
if(n<m)
{
m=n;
}
long int a[n];
for(i=0;i<n;i++)
{
scanf("%ld",&a[i]);
}
for(i=0;i<m;i++)
{
for(j=n-1;j>i;j--)
{
if(a[j]>a[j-1])
{
t=a[j];
a[j]=a[j-1];
a[j-1]=t;
}
}
}
for(i=0;i<m-1;i++)
{
printf("%ld ",a[i]);
}
printf("%ld",a[m-1]);
return 0;
}
7-3 点赞狂魔 (25 分)
微博上有个“点赞”功能,你可以为你喜欢的博文点个赞表示支持。每篇博文都有一些刻画其特性的标签,而你点赞的博文的类型,也间接刻画了你的特性。然而有这么一种人,他们会通过给自己看到的一切内容点赞来狂刷存在感,这种人就被称为“点赞狂魔”。他们点赞的标签非常分散,无法体现出明显的特性。本题就要求你写个程序,通过统计每个人点赞的不同标签的数量,找出前3名点赞狂魔。
输入格式:
输入在第一行给出一个正整数N(≤100),是待统计的用户数。随后N行,每行列出一位用户的点赞标签。格式为“Name K F 1 ⋯F K ”,其中Name是不超过8个英文小写字母的非空用户名,1≤K≤1000,F i(i=1,⋯,K)是特性标签的编号,我们将所有特性标签从 1 到 10 7编号。数字间以空格分隔。
输出格式:
统计每个人点赞的不同标签的数量,找出数量最大的前3名,在一行中顺序输出他们的用户名,其间以1个空格分隔,且行末不得有多余空格。如果有并列,则输出标签出现次数平均值最小的那个,题目保证这样的用户没有并列。若不足3人,则用-补齐缺失,例如mike jenny -就表示只有2人。
输入样例:
5
bob 11 101 102 103 104 105 106 107 108 108 107 107
peter 8 1 2 3 4 3 2 5 1
chris 12 1 2 3 4 5 6 7 8 9 1 2 3
john 10 8 7 6 5 4 3 2 1 7 5
jack 9 6 7 8 9 10 11 12 13 14
结尾无空行
输出样例:
jack chris john
结尾无空行
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
typedef struct node{
char name[11];
int *expression;
int count;
int k;
}node;
node Like[101];
int main()
{
int i,j,n,num,k,label;
node snap;
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%s %d",Like[i].name,&Like[i].k);
Like[i].expression=(int *)malloc(sizeof(int)*Like[i].k);
if(Like[i].expression==NULL)
return -1;
for(j=0;j<Like[i].k;j++)
{
scanf("%d",&num);
label=0;
for(k=0;k<Like[i].count;k++)
{
if(Like[i].expression[k]==num)
{
label++;
break;
}
}
if(!label)
{
Like[i].count++;
Like[i].expression[k]=num;
}
label=0;
}
}
for(i=0;i<n;i++){
for(j=1;j<n-i;j++){
if(Like[j-1].count<=Like[j].count){
if(Like[j-1].count==Like[j].count){
int num=Like[j-1].k>Like[j].k?j:j-1;
snap=Like[num];
Like[num]=Like[(num==j?j-1:j)];
Like[(num==j?j-1:j)]=snap;
}
else{
snap=Like[j-1];
Like[j-1]=Like[j];
Like[j]=snap;
}
}
}
}
for(i=0;i<3;i++)
{
if(i>=n)
printf(" -");
else
{
if(i==0)
printf("%s",Like[i].name);
else
printf(" %s",Like[i].name);
}
}
return 0;
}
7-4 插入排序还是归并排序 (25 分)
根据维基百科的定义:
插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。
归并排序进行如下迭代操作:首先将原始序列看成 N 个只包含 1 个元素的有序子序列,然后每次迭代归并两个相邻的有序子序列,直到最后只剩下 1 个有序的序列。
现给定原始序列和由某排序算法产生的中间序列,请你判断该算法究竟是哪种排序算法?
输入格式:
输入在第一行给出正整数 N (≤100);随后一行给出原始序列的 N 个整数;最后一行给出由某排序算法产生的中间序列。这里假设排序的目标序列是升序。数字间以空格分隔。
输出格式:
首先在第 1 行中输出Insertion Sort表示插入排序、或Merge Sort表示归并排序;然后在第 2 行中输出用该排序算法再迭代一轮的结果序列。题目保证每组测试的结果是唯一的。数字间以空格分隔,且行首尾不得有多余空格。
输入样例 1:
10
3 1 2 8 7 5 9 4 6 0
1 2 3 7 8 5 9 4 6 0
结尾无空行
输出样例 1:
Insertion Sort
1 2 3 5 7 8 9 4 6 0
结尾无空行
输入样例 2:
10
3 1 2 8 7 5 9 4 0 6
1 3 2 8 5 7 4 9 0 6
结尾无空行
输出样例 2:
Merge Sort
1 2 3 8 4 5 7 9 0 6
结尾无空行
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n, pos, i, j, range = 2;
int a[105], b[105];
cin >> n;
for (i = 0; i < n; i++)
scanf("%d", &a[i]);
for (i = 0; i < n; i++)
scanf("%d", &b[i]);
for (i = 1; i < n; i++)
{
if (b[i] < b[i - 1])
break;
}
for (j = i; j < n; j++)
{
if (a[j] != b[j])
break;
}
if (j == n)
{
printf("Insertion Sort\n");
sort(b, b + i + 1);
}
else
{
printf("Merge Sort\n");
while (1)
{
for (i = 0; i < n / range; i++)
sort(a + i * range, a + (i + 1) * range);
sort(a + i * range, a + n);
for (i = 0; i < n; i++)
{
if (a[i] != b[i])
break;
}
if (i == n)
{
range *= 2;
for (i = 0; i < n / range; i++)
sort(b + i * range, b + (i + 1) * range);
sort(b + i * range, b + n);
break;
}
range *= 2;
}
}
printf("%d", b[0]);
for (int i = 1; i < n; i++)
printf(" %d", b[i]);
printf("\n");
return 0;
}
7-5 逆序对 (15 分)
给定一个长度为n的整数数列,请你计算数列中的逆序对的数量。
逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i < j 且 a[i] > a[j],则其为一个逆序对;否则不是。
输入格式:
第一行包含整数n,表示数列的长度;第二行包含 n 个整数,表示整个数列。(1≤n≤100000)
输出格式:
输出一个整数,表示逆序对的个数。
输入样例:
6
2 3 4 5 6 1
结尾无空行
输出样例:
5
结尾无空行
#include <stdio.h>
#define N 1000000
int n,a[N],b[N];
long long cnt=0;
void f(int L,int R)
{
if(L==R) return;
int m=(L+R)/2;
int k1=L,k2=m+1,k=L;
f(L,m);
f(m+1,R);
while(k1<=m&&k2<=R)
{
if(a[k1]<=a[k2])
{
b[k]=a[k1];
k++,k1++;
}
else{
b[k]=a[k2];
k++,k2++;
cnt=cnt+m-k1+1;
}
}
while(k1<=m)
{
b[k]=a[k1];
k++,k1++;
}
while(k2<=R)
{
b[k]=a[k2];
k++,k2++;
}
for(int i=L;i<=R;i++)
a[i]=b[i];
}
int main()
{
int i ;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
f(1,n);
printf("%lld",cnt);
return 0;
}
7-7 堆排序 (10 分)
给定一个整数序列,请按非递减序输出采用堆排序的各趟排序后的结果。
输入格式:
测试数据有多组,处理到文件尾。每组测试数据第一行输入一个整数n(1≤n≤100),第二行输入n个整数。
输出格式:
对于每组测试,输出若干行,每行是一趟排序后的结果,每行的每两个数据之间留一个空格。
输入样例:
4
8 7 2 1
输出样例:
7 1 2 8
2 1 7 8
1 2 7 8
#include <stdio.h>
#include <stdlib.h>
int a[105], n;
void swap(int k[],int i,int j)
{
int temp=k[i];
k[i]=k[j];
k[j]=temp;
}
void print()
{
printf("%d", a[1]);
for (int i = 2; i <= n; i++)
printf(" %d", a[i]);
printf("\n");
}
void sift(int k, int end)
{
int i = k, j = 2 * i;
while (j <= end)
{
if (j < end && a[j] < a[j + 1])
j++;
if (a[i] < a[j])
swap(a,i,j);
i = j;
j = 2 * i;
}
}
void heapsort(int n)
{
for (int k = n / 2; k >= 1; k--)
sift(k, n);
for (int k = 1; k < n; k++)
{
swap(a,1,n-k+1);
sift(1, n - k);
print();
}
}
int main()
{
while (~scanf("%d", &n))
{
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
heapsort(n);
}
return 0;
}
7-8 快速排序 (10 分)
给定一个整数序列,请按非递减序输出采用快速排序(递归法)的各趟排序后的结果。注意:每趟排序以排序区间的首元素为枢轴(支点)。
输入格式:
测试数据有多组,处理到文件尾。每组测试数据第一行输入一个整数n(1≤n≤100),第二行输入n个整数。
输出格式:
对于每组测试,输出若干行,每行是一趟排序后的结果,每行的每两个数据之间留一个空格。
输入样例:
4
8 7 2 1
输出样例:
1 7 2 8
1 7 2 8
1 2 7 8
#include <stdio.h>
#include <stdlib.h>
void swap(int k[],int i,int j)
{
int temp=k[i];
k[i]=k[j];
k[j]=temp;
}
int n;
int a[105];
void print()
{
for (int i = 0; i < n; i++)
{
printf("%d", a[i]);
if (i == n - 1)
printf("\n");
else
printf(" ");
}
}
int cut(int l, int r)
{
int i, j, t;
i = l;
j = r;
while (i < j)
{
while (i < j && a[i] <= a[j])
j--;
if (i < j)
{
swap(a,i,j);
i++;
}
while (i < j && a[i] <= a[j])
i++;
if (i < j)
{
swap(a,i,j);
j--;
}
}
return i;
}
void quicksort(int l, int r)
{
int k;
if (l < r)
{
k = cut(l, r);
print();
quicksort(l, k - 1);
quicksort(k + 1, r);
}
}
int main()
{
while (~scanf("%d", &n))
{
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
quicksort(0, n - 1);
}
return 0;
}
7-9 归并排序 (20 分)
知识点:归并排序
给定你一个长度为 n 的整数数列。
请你使用归并排序对这个数列按照从小到大进行排序。
并将排好序的数列按顺序输出。
输入格式:
输入共两行,第一行包含整数 n(1≤n≤100000)。
第二行包含 n 个整数(所有整数均在 1∼10^9 范围内),表示整个数列。
输出格式:
输出共一行,包含 n 个整数,表示排好序的数列。
输入样例:
5
3 1 2 4 5
结尾无空行
输出样例:
1 2 3 4 5
结尾无空行
#include<stdio.h>
#include<stdio.h>
void merge(int num1[],int num2[],int start,int mid,int end )
{
int i=start,j=mid+1,k=start;
while(i!=mid+1 && j!=end+1)
{
if(num1[i]>=num1[j])
num2[k++]=num1[j++];
else
num2[k++]=num1[i++];
}
while(i!=mid+1)
{
num2[k++]=num1[i++];
}
while(j!=end+1)
{
num2[k++]=num1[j++];
}
for(i=start; i<=end; i++)
num1[i] = num2[i];
}
void mergeSort(int num1[],int num2[],int start,int end)
{
int mid;
if(start<end)
{
mid=(start+end)/2;
mergeSort( num1, num2, start, mid);
mergeSort( num1, num2,mid+1, end);
merge(num1,num2,start,mid,end);
}
}
int main()
{
int i,n;
scanf("%d",&n);
int num1[n];
int num2[n];
for(i=0; i<n; i++)
{
scanf("%d", &num1[i]);
}
mergeSort(num1,num2,0,n-1 );
for(i=0; i<n; i++)
printf("%d ", num1[i]);
printf("\n");
return 0;
}
7-10 逆序对的数量 (20 分)
知识点:归并排序
给定一个长度为 n 的整数数列,请你计算数列中的逆序对的数量。
逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i<j 且 a[i]>a[j],则其为一个逆序对;否则不是。
输入格式:
第一行包含整数 n(1≤n≤100000),表示数列的长度。
第二行包含 n 个整数,表示整个数列,数列中的元素的取值范围 [1~10^9]。
输出格式:
请在这里描述输出格式。例如:对每一组输入,在一行中输出A+B的值。
输入样例:
6
2 3 4 5 6 1
结尾无空行
输出样例:
5
作者 陆泓宇
单位 韩山师范学院
代码长度限制 16 KB
时间限制 1000 ms
内存限制 64MB
#include <stdio.h>
#define N 1000000
int n,a[N],b[N];
long long cnt=0;
void f(int L,int R)
{
if(L==R) return;
int m=(L+R)/2;
int k1=L,k2=m+1,k=L;
f(L,m);
f(m+1,R);
while(k1<=m&&k2<=R)
{
if(a[k1]<=a[k2])
{
b[k]=a[k1];
k++,k1++;
}
else{
b[k]=a[k2];
k++,k2++;
cnt=cnt+m-k1+1;
}
}
while(k1<=m)
{
b[k]=a[k1];
k++,k1++;
}
while(k2<=R)
{
b[k]=a[k2];
k++,k2++;
}
for(int i=L;i<=R;i++)
a[i]=b[i];
}
int main()
{
int i ;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
f(1,n);
printf("%lld",cnt);
return 0;
}
7-11 寻找第k小的数 (10 分)
给定若干整数,请设计一个高效的算法,确定第k小的数。
输入格式:
测试数据有多组,处理到文件尾。每组测试数据的第1行输入2个整数n,k(1≤k≤n≤1000000)。第2行输入n个整数,每个数据的取值范围在0到1000000之间。
输出格式:
对于每组测试,输出第k小的数。
输入样例:
5 3
1 2 2 2 1
9 3
1 2 3 4 5 6 9 8 7
输出样例:
2
3
提示:
如果提交后超时,请注意需要设计的是高效的算法!如果你初学《数据结构》,暂时设计不出来,请学完相关知识再回头来做。 也可以使用STL之sort、nth_element函数求解。 另外,由于输入数据特别多,为减少输入数据的耗时,建议使用以下的输入外挂函数:
void scan_d(int &num)
{
char in;
in=getchar();
while(in<‘0’||in>‘9’) in=getchar();
num=in-‘0’;
while(in=getchar(),in>=‘0’&&in<=‘9’){num*=10,num+=in-‘0’;}
}
调用方法如下:
int n;
scan_d(n);
作者 usx程序设计类课程组
单位 绍兴文理学院
代码长度限制 16 KB
时间限制 400 ms
内存限制 64MB
#include <stdio.h>
#include <stdlib.h>
int a[1000005];
int cmp(const void *a,const void *b)
{
return *(int*)a-*(int*)b;
}
int main()
{
int n, k;
while (~scanf("%d %d", &n, &k))
{
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
qsort(a,n,sizeof(int),cmp);
printf("%d\n", a[k - 1]);
}
return 0;
}