PAT (Basic Level) Practice (中文)1055 集体照 (25 分)
题目描述:
拍集体照时队形很重要,这里对给定的 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排人名,其间以空格分隔,行末不得有多余空格。注意:假设你面对拍照者,后排的人输出在上方,前排输出在下方。
输入样例:
10 3
Tom 188
Mike 170
Eva 168
Tim 160
Joe 190
Ann 168
Bob 175
Nick 186
Amy 160
John 159
输出样例:
Bob Tom Joe Nick
Ann Mike Eva
Tim Amy John
题目要求:
作者 CHEN, Yue
单位 浙江大学
代码长度限制 16 KB
时间限制 400 ms
内存限制 64 MB
解题思路:
首先是对所有人员的处理 ,需要按照题目要求对输入的人员的人名以及身高进行排序。这里我利用的是 struct 结构体 和 sort 函数 分别进行存储数据和排序。
// 第一存储姓名和身高的结构体 peo typedef 的好处自行体会哦!
typedef struct peo{
string name ; // string 类型 用来存储人名 name (因为 string 的比较就是字典序)
int high ; // int 类型 用来存储与 name 对应的 身高值 high
} Peo;
// 为满足题目要求,手撕与 sort 配合使用的 cmp 函数
bool cmp(Peo a , Peo b){
if(a.high == b.high)
return a.name < b.name ; // 身高相同的时候, 按照人名的 字典序升序进行排列
return a.high > b.high ; // 身高不等时,按照身高的降序排列
}
sort(stu , stu + n , cmp) ; // 对输入的数据 按要求排序,n 为输人的需要排序的人数
然后是将上述中排好序的人,进行排集体照的站位。总共有 k 排,除最后一排外,其余排的人数 x = n / k ,故最后一排的人数为 y = n - (k - 1) * x ; 其实接下来就变成了设计一个函数来排好第 m 排的集体照站位即可。
// 定义一个二维的 string 类型的数组,用来存储 集体照的站位
string s[10][10005];
// 设计一个排集体照第 k 行站位的 函数
void sortPeople(int row , int num){ // 参数说明: 第 row 排 以及该排的人数 num 个
int t = num / 2 + 1 ; // 首先找到 这一排最高的那个人的站位 t
// 计算出在排这一排之前,我们已经有多少人的站位已确定
int index = (row == 0) ? 0 : (row - 1) * x + y ;
// 将剩下最高的人,安置他的站位 t -1 (t - 1)是因为从 0 开始计算
s[row][t - 1] = stu[index].name ;
// 排好中间人后,按照题目要求,中间人为轴先右后左,(对应我们存数据的先低位后高位)
// 先将他的低位排好,因为是先低位后高位,依次轮流 , j 的初值为 1 , 步长为 2
for( int i = t - 2 , j = 1 ; i >= 0 ; i -- , j += 2){
s[row][i] = stu[index + j].name ;
}
// 再将他的高位排好,因为是先低位后高位,依次轮流 , j 的初值为 2 , 步长为 2
for( int i = t , j = 2 ; i < num ; i ++ , j += 2){
s[row][i] = stu[index + j].name ;
}
// 排完左边和右边,本排的 集体照站位 已经全部完成。
}
最后是对每一排调用一下 sortPeople() 函数
// 最后一排的人数与其他排不一致,先排好最后一排
sortPeople(0 , y) ;
// 剩下的 k - 1 排,直接利用 for 循环进行调用即可
for(int i = 1 ; i < k ; i ++){
sortPeople(i , x) ;
}
完整代码:
#include<bits/stdc++.h>
using namespace std ;
#define MAX 10005
typedef struct peo {
string name ;
int high ;
} Peo ;
Peo stu[MAX] ;
int n , k , x , y ;
string s[10][MAX];
bool cmp(Peo a , Peo b){
if(a.high == b.high)
return a.name < b.name ;
return a.high > b.high ;
}
// 从最后一排开始,往前排
void sortPeople(int row , int num){ // 第 row 排 以及该排的人数 num 个
int t = num / 2 + 1 ;
int index = (row == 0) ? 0 :(row - 1 * x + y ;// 前面已经排了index个人了
s[row][t - 1] = stu[index].name ;
for( int i = t - 2 , j = 1 ; i >= 0 ; i -- , j += 2){
s[row][i] = stu[index + j].name ;
}
for( int i = t , j = 2 ; i < num ; i++ ,j += 2){
s[row][i] = stu[index + j].name ;
}
}
int main(){
cin >> n >> k ;
for(int i = 0 ; i < n ; i++){
cin>>stu[i].name>>stu[i].high;
}
sort(stu , stu + n , cmp) ;// 按照题目要去排序;
// for(int i = 0 ; i < n ; i++){
// cout<<stu[i].name<<stu[i].high<<endl;
// }
x = n / k ; // 前 k-1排人数
y = n - (k - 1 ) * x; // 最后一排的人数
sortPeople(0 , y) ;
for(int i = 1 ; i < k ; i++){
sortPeople(i , x) ;
}
cout<<s[0][0] ;
for(int i = 1 ; i < y ; i++){
cout<<" "<<s[0][i] ;
}
for(int i = 1 ; i < k ; i++){
cout<<endl ;
cout<<s[i][0] ;
for(int j = 1 ; j < x ; j ++){
cout<<" "<<s[i][j] ;
}
}
cout<<endl;
return 0;
}