top1编程
← 返回题目
题解

香山合影

1 条题解

  • 0
    @ 2026-8-5 22:10:04

    P4638 香山合影(基础)

    解题思路

    这道题考察的是分组排序。同学们去香山玩,要站成一排合影。规则是:男生全部站在左边,并且从矮到高排;女生全部站在右边,并且从高到矮排。所有人的身高都不同。我们只要把每个人的性别和身高读进来,按规则排好队,再把身高从左到右输出就行。

    思路很直接:把男生和女生先分开,存到两个不同的数组里。然后分别排序——男生从矮到高(升序),女生从高到矮(降序)。最后先输出全部男生的身高,再输出全部女生的身高,中间用空格隔开,就是拍照者眼中从左到右的顺序。

    怎么区分男女呢?输入里性别是字符串 male 或 female。我们不需要完整比较整个字符串,只要看第一个字符:m 开头的就是男生,f 开头的就是女生。

    排序方法:n 最大只有 40,人数很少,用简单的冒泡排序就足够了。冒泡排序的思想是:从头到尾两两比较相邻的两个数,如果顺序不对就交换,这样每趟下来最大的(或最小的)数就会"冒泡"到它该在的位置,重复若干趟后整个数组就有序了。男生组按照"前一个比后一个高就交换"来排,最后得到从矮到高的顺序;女生组反过来,按照"前一个比后一个矮就交换"来排,得到从高到矮的顺序。

    输出时有两个细节要注意。第一,身高是浮点数,要求保留两位小数,比如 1.72 米。可以自己写一个输出函数,把身高乘以 100 四舍五入后拆成整数部分和小数部分,再补零输出;第二,相邻两个身高之间要用一个空格隔开,但第一个身高前面不能有空格,最后一个身高输出后要换行。

    边界情况:题目保证至少有 1 个男生和 1 个女生,且 n 在 2 到 40 之间,所以两个数组都一定非空,不会出现"有一边没人"的情况。

    参考代码

    // 把男生按从矮到高、女生按从高到矮排列后输出。
    #include <iostream>
    using namespace std;
    
    // 输出保留两位小数的身高。
    void out2(double x) {
        long long v = (long long)(x * 100 + 0.5); // 把身高放大100倍并四舍五入。
        int d = (int)(v % 100); // 取出小数部分。
        cout << v / 100 << '.'; // 输出整数部分和小数点。
        if (d < 10) cout << 0; // 一位小数时补零。
        cout << d; // 输出两位小数。
    }
    
    int main() {
        int n; // 总人数。
        double male[45]; // 保存男生身高。
        double female[45]; // 保存女生身高。
        int mc = 0; // 男生人数。
        int fc = 0; // 女生人数。
        int i; // 循环变量。
        cin >> n; // 读入总人数。
        for (i = 0; i < n; i++) { // 读入每个人的信息。
            char sex[10]; // 性别字符串。
            double h; // 当前人的身高。
            cin >> sex >> h; // 读入性别和身高。
            if (sex[0] == 'm') { // male开头是男生。
                male[mc] = h; // 保存男生身高。
                mc++; // 男生人数加一。
            } else { // 否则是女生。
                female[fc] = h; // 保存女生身高。
                fc++; // 女生人数加一。
            }
        }
        for (i = 0; i < mc - 1; i++) { // 排序男生身高。
            int j; // 内层循环变量。
            for (j = 0; j < mc - 1 - i; j++) { // 比较相邻男生。
                if (male[j] > male[j + 1]) { // 男生应从矮到高。
                    double t = male[j]; // 暂存一个男生身高。
                    male[j] = male[j + 1]; // 较矮者向前。
                    male[j + 1] = t; // 较高者向后。
                }
            }
        }
        for (i = 0; i < fc - 1; i++) { // 排序女生身高。
            int j; // 内层循环变量。
            for (j = 0; j < fc - 1 - i; j++) { // 比较相邻女生。
                if (female[j] < female[j + 1]) { // 女生应从高到矮。
                    double t = female[j]; // 暂存一个女生身高。
                    female[j] = female[j + 1]; // 较高者向前。
                    female[j + 1] = t; // 较矮者向后。
                }
            }
        }
        for (i = 0; i < mc; i++) { // 输出男生队伍。
            if (i > 0) cout << ' '; // 身高之间用空格隔开。
            out2(male[i]); // 输出男生身高。
        }
        for (i = 0; i < fc; i++) { // 输出女生队伍。
            cout << ' '; // 男生和女生之间也用空格隔开。
            out2(female[i]); // 输出女生身高。
        }
        cout << '\n'; // 输出换行。
        return 0; // 程序正常结束。
    }
    

    复杂度分析

    时间上,男生和女生两组分别做冒泡排序,最坏情况下每组的排序时间与人数平方成正比,所以总时间复杂度是 O(n²)。但 n 最大只有 40,40²=1600 次操作,非常快。如果数据量再大,可以换成 O(n log n) 的快速排序。空间上,用两个大小固定的数组保存男生和女生身高,空间复杂度是 O(n)。

    • 1