whenever

  • Home

  • Tags21

  • Categories6

  • Archives122

  • About

PAT乙级1055 || 集体照(详解,C/C++示例,测试点分析)

Posted on 2019-10-01 In PAT

集体照

题目描述

拍集体照时队形很重要,这里对给定的 N 个人 K 排的队形设计排队规则如下:

  • 每排人数为 N/K(向下取整),多出来的人全部站在最后一排;
  • 后排所有人的个子都不比前排任何人矮;
  • 每排中最高者站中间(中间位置为 m/2+1,其中 m 为该排人数,除法向下取整);
  • 每排其他人以中间人为轴,按身高非增序,先右后左交替入队站在中间人的两侧(例如5人身高为190、188、186、175、170,则队形为175、188、190、186、170。这里假设你面对拍照者,所以你的左边是中间人的右边);
  • 若多人身高相同,则按名字的字典序升序排列。这里保证无重名。

现给定一组拍照人,请编写程序输出他们的队形。

输入格式

每个输入包含 1 个测试用例。每个测试用例第 1 行给出两个正整数 N(≤$10^4$,总人数)和 K(≤10,总排数)。随后 N 行,每行给出一个人的名字(不包含空格、长度不超过 8 个英文字母)和身高([30, 300] 区间内的整数)。

输出格式

输出拍照的队形。即K排人名,其间以空格分隔,行末不得有多余空格。注意:假设你面对拍照者,后排的人输出在上方,前排输出在下方。

输入样例

1
2
3
4
5
6
7
8
9
10
11
10 3
Tom 188
Mike 170
Eva 168
Tim 160
Joe 190
Ann 168
Bob 175
Nick 186
Amy 160
John 159

输出样例

1
2
3
Bob Tom Joe Nick
Ann Mike Eva
Tim Amy John

问题解决

解题思想

用结构体变量来存入每个人的名字和身高。输入相关信息后,先按身高升序排序,身高相同时按名字字典序降序排序。下面代码采用从后排往前排排队的策略,每排一行输出一行。具体过程如下:

  1. 排好序的数组p[]中当前最后一位(身高最高者)取出,排在中间;
  2. 接着取下一位,排在右边(面向拍照者);
  3. 取下一位,排在左边(面向拍照者);
  4. 重复2,3过程,直到排够该排的人数;
  5. 按格式输出该排人名;
  6. 重复过程1,2,3,4,5,直到排完。

知识拓展

strcmp()函数的返回值,这里需要提醒一下:
对于strcmp(d.name,b.name)而言,当字典序d.name == b.name时,函数将返回0;当字典序d.name > b.name时,函数将返回正数;当字典序d.name < b.name时,函数将返回负数。
下面代码的cmp函数,一开始我在处理按字典序降序排序时写为:

1
return strcmp(d.name,b.name) == 1? 1 : 0;

这是犯了当字典序d.name > b.name时,函数将返回1的错误,正确的写法是:

1
return strcmp(d.name,b.name) > 0? 1 : 0;

代码示例(C/C++)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 10001;
struct height
{
char name[9];
int h;
}p[maxn];
bool cmp(height d,height b)
{
if(d.h != b.h){
return d.h < b.h;
}
else{
return strcmp(d.name,b.name) > 0? 1 : 0; //按字典序降序排序
}
}
int main()
{
int n,k;
char a[maxn][9];
scanf("%d%d",&n,&k);
for(int i = 0; i < n; i++){
scanf("%s%d",p[i].name,&p[i].h); //注意
}
sort(p,p + n,cmp);
int num[11];
num[k] = 0;
num[k - 1]= n / k + n % k; //最后一排的人数
for(int i = 0; i < k - 1; i++){
num[i] = n / k; //其它排的人数
}
int w = 0,s = 0;
for(int i = 0; i < k; i++){
w += num[k - i];
s += num[k - i - 1];
strcpy(a[num[k - i - 1] / 2],p[n - w - 1].name); //排中间位置
int x = num[k - i - 1] / 2 - 1,y = num[k - i - 1] / 2 + 1;
for(int j = n - w - 2; j >= n - s; ){
if(x >= 0&&j >= n - s){ //先向左排(面向拍照者是向右)
strcpy(a[x--],p[j--].name);
}
if(y <= num[k - i - 1] - 1&&j >= n - s){ //再向右排(面向拍照者是向左)
strcpy(a[y++],p[j--].name);
}
}
for(int j = 0; j < num[k - i - 1]; j++){
printf("%s",a[j]);
if(j != num[k - i - 1] - 1){
printf(" ");
}
}
printf("\n");
}
return 0;
}

题目来源:PAT乙级1055
作者:CHEN, Yue
单位:浙江大学

稀罕作者
Mengzhao Wang WeChat Pay

WeChat Pay

Mengzhao Wang Alipay

Alipay

# C/C++ # PAT # 编程
PAT乙级1054 || 求平均值(详解,C/C++示例,测试点分析)
PAT乙级1056 || 组合数的和(详解,C/C++示例,测试点分析)
  • Table of Contents
  • Overview
Mengzhao Wang

Mengzhao Wang

Try? All the way !
122 posts
6 categories
21 tags
  1. 1. 集体照
    1. 1.1. 题目描述
    2. 1.2. 输入格式
    3. 1.3. 输出格式
    4. 1.4. 输入样例
    5. 1.5. 输出样例
    6. 1.6. 问题解决
      1. 1.6.1. 解题思想
      2. 1.6.2. 知识拓展
      3. 1.6.3. 代码示例(C/C++)
© 2021 Mengzhao Wang