PAT 乙级 1055.集体照 C++/Java

孤街醉人 提交于 2020-01-25 17:59:05

题目来源

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

  • 每排人数为 /(向下取整),多出来的人全部站在最后一排;

  • 后排所有人的个子都不比前排任何人矮;

  • 每排中最高者站中间(中间位置为 /,其中 m 为该排人数,除法向下取整);

  • 每排其他人以中间人为轴,按身高非增序,先右后左交替入队站在中间人的两侧(例如5人身高为190、188、186、175、170,则队形为175、188、190、186、170。这里假设你面对拍照者,所以你的左边是中间人的右边);

  • 若多人身高相同,则按名字的字典序升序排列。这里保证无重名。

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

输入格式:

每个输入包含 1 个测试用例。每个测试用例第 1 行给出两个正整数 N(≤,总人数)和 K(≤,总排数)。随后 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

分析:

第三排:Bob Tom Joe Nick
第二排:Ann Mike Eva
第一排:Tim Amy John单独看第三排的人的身高Bob    Tom  Joe  Nick175    188  190  186假定最开始他们是有序的即:190  188  186  175题目要求的是,最高的在中间,按身高非增序,先右后左交替入队站在中间人的两侧(这里的左右,是相对于中间人的左右,即。我们面对着中间人,对我们来说就是先左后右)什么意思呢?首先,我们先把最高的放中间,190接着,先左后右的入队,下一个 188,变成 188 190然后,186 入队, 变成 188 190 186以此类推可以得到:175 188 190 186稍微分析一下可以发现这个身高排名规律:175 188 190 186no4 no2 no1 no3(就类似领奖台的那种,冠亚季军站旁边)假定条件:t - 用来记录当前一排的最大值的下标,初始化为0m - 当前一排的人数res - 存放当前一排的人的名字peoples - 所有人的名字、身高(已排序,高到低)1. 首先: res[m/2] = 身高最高的; // res[m/2] = 190 2. 遍历 188 186 175,将 188 和 175 放在 190 的左边
int j = 0;
for (int i = t + 1; i < m + t; i += 2) {
    res[j++] = peoples[i].name;
}

 i += 2 就是隔一个取一个

 m + t 就可以理解为是一个范围,每次循环,输出peoples数组 [ t, m + t)的内容(看后面解析)

 i = t + 1 此时 t = 0,即从 peoples[1]开始,隔一个取一个(peoples[0]已经放到了中间)

第一行是 m = 4, t = 0, 那么这一排的人在peoples中的下标就是 [ 0 , 3)

 res 数组变成了 188 175 190

3. 这时候发现,我们要的是 175 188 190,怎么办呢?reverse翻转 reverse(res.begin(), res.begin() + j); 4. 接着我们来处理 190 的右边,和第二步是一样的做法,需要注意的是,执行完第二部之后,另 j += 1 ,因为此时 j == m/2 for (int i = t + 2; i < m + t; i += 2) { res[j++] = peoples[i].name; }    这种情况就不用 reverse 了,因为是按高到低的顺序放到右边的5. 输出当前一排(没啥好说的了,注意格式6. 更新 row 和 t 的值   row--;    t = m + t   理解一下 t = m + t

怎么理解 t = m + t 

  1. 当 m = 4, t = 0 时:输出的是  peoples[0] ~ peoples[3] ,更新 t = m + t = 4 + 0 = 4;
  2. 当 m = 3, t = 4 时:输出的是  peoples[4] ~ peoples[6] ,更新 t = m + t = 3 + 4 = 7;
  3. 当 m = 3, t = 7 时:输出的是  peoples[7] ~ peoples[9] .....

C++实现:

#include <iostream>
#include <string>
#include<algorithm>
#include <stack>
#include <queue>
#include <unordered_map>
#include <iomanip>
using namespace std;

/*
190、188、186、175、170

-> 175、188、190、186、170
-> no4、no2、no1、no3、no5
*/

typedef struct Person {
    string name;
    int height;
}Person;

bool cmp(Person a, Person b) {
    if (a.height != b.height) {
        return a.height > b.height;
    }
    else {
        return a.name < b.name;
    }
}

int main() {
    int K;    // 总排数
    int N;    // 总人数
    cin >> N >> K;
    vector<Person> peoples(N);
    for (int i = 0; i < N; ++i) {
        cin >> peoples[i].name >> peoples[i].height;
    }

    sort(peoples.begin(), peoples.end(), cmp);

    int t = 0;    
    int row = K;    // 当前是第几排
    int m = 0;        // 当前一排的人数
    
    while (row) {
        if (row == K) {
            m = N - (K - 1)* N / K;    // N÷K是每排的人数
        }
        else {
            m = N / K;
        }

        // 数组都排好序了
        // 190, 188, 186, 175, 170, 168, 168, 160, 160, 159
        // N = 10, K = 3
        // row = 3
        // m = N - (K - 1)* N / K
        //   = 10 - (3 - 1) * 10 / 3
        //   = 10 - 2 * 3
        //   = 4    最后一排有4个人

        vector<string> res(m);    //保存目前一排的人的名字
        // t = 0, peoples[0]是最大的190,把它放到中间,也就是m/2
        res[m / 2] = peoples[t].name;

        // 接着把188,175放到res[m/2]的左边(保持顺序175 188 res[m/2]),即:隔一个就取一个放到左边
        int j = 0;
        for (int i = t + 1; i < m + t; i += 2) {
            res[j++] = peoples[i].name;
        }
        reverse(res.begin(), res.begin() + j);

        // 把186,放到res[m/2]的右边(保持顺序),即:隔一个就取一个放到右边
        j += 1;
        for (int i = t + 2; i < m + t; i += 2) {
            res[j++] = peoples[i].name;
        }
        // 输出
        cout << res[0];
        for (int i = 1; i < m; ++i) {
            cout << ' ' << res[i];
        }
        cout << endl;
        t = t + m;
        row--;
    }
    return 0;
}

 

 

Java实现:

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!