题干:
拍集体照时队形很重要,这里对给定的N个人K排的队形设计排队规则如下:
-
每排人数为N/K(向下取整),多出来的人全部站在最后一排;
-
后排所有人的个子都不比前排任何人矮;
-
每排中最高者站中间(中间位置为m/2+1,其中m为该排人数,除法向下取整);
-
每排其他人以中间人为轴,按身高非增序,先右后左交替入队站在中间人的两侧(例如5人身高为190、188、186、175、170,则队形为175、188、190、186、170。这里假设你面对拍照者,所以你的左边是中间人的右边);
-
若多人身高相同,则按名字的字典序升序排列。这里保证无重名。
现给定一组拍照人,请编写程序输出他们的队形。
输入格式:
每个输入包含1个测试用例。每个测试用例第1行给出两个正整数N(<=10000,总人数)和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
这道题的思路可以先将身高存储到大数组中,并排好序,然后再对每一行进行处理。
每一行处理的方法为:先让m等于中间的人在每一行的数组中的下标,然后再让m变成m-1,m+2,m-3。。。将排好序的大数组依次赋值进去即可。
具体代码如下:
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef struct {
string name;
int high;
} person;
bool cmp(person a, person b){
if(a.high != b.high)
return a.high < b.high;
else return a.name > b.name;
}
int main()
{
int sum, line, line_p; //sum为人数,line为有几行,line_p为每行的人数,last_line为最后一行的人数
cin >> sum >> line; //sum是总人数,line是行数
string result[10010]; //result存储每次输出的临时数据
int lines[15] = {0}; //每行的人数
person p[10010]; //存储输入的数据
line_p = sum / line; //每行的人数(最后一排除外)
for(int i = 0; i < sum; i++){
cin >> p[i].name >> p[i].high; //依次读入数据
}
sort(p, p + sum, cmp); //将数组p中的元素按照题意进行排序 小->大
int s = sum; //s为临时变量
//下面这一段循环可以用memset替代,只要注意特殊考虑最后一行就行
for(int i = 0; i < line; i++){
if(i != line - 1){ //只要不是最后一行,这一行的人数就是line_p
lines[i] = line_p;
s -= line_p;
}else{ //如果是最后一行
lines[i] = s; //最后一行人数等于剩下的人数
}
} //到此,lines内部元素为从前到后排好序了
int n, it = sum - 1, middle; //n是系数,cnt用来计数,it为当前在数组的位置,middle用来存储中间的人的下标
for(int i = line - 1; i >= 0; i--){ //从后到前进行排列
n = 1; middle = (lines[i] / 2); //每次循环初始化一遍数据
for(int j = 0; j < lines[i]; j++){
middle += j * n;
result[middle] = p[it--].name;
n *= -1;
}
for(int k = 0; k < lines[i]; k++){
cout<<result[k];
if(k != lines[i] - 1) cout<<' ';
}
cout<<endl;
}
return 0;
}