题解:洛谷 P14358 座位

【题目来源】

洛谷:P14358 [CSP-J 2025] 座位 / seat(民间数据) - 洛谷

【题目描述】

CSP-J 2025 第二轮正在进行。小 R 所在的考场共有 \(n \times m\) 名考生,其中所有考生的 CSP-J 2025 第一轮成绩互不相同。所有 \(n \times m\) 名考生将按照 CSP-J 2025 第一轮的成绩,由高到低蛇形分配座位,排列成 \(n\) \(m\) 。具体地,设小 R 所在的考场的所有考生的成绩从高到低分别为 \(s_1 > s_2 > \dots > s_{n \times m}\),则成绩为 \(s_1\) 的考生的座位为第 1 \(1\) ,成绩为 \(s_2\) 的考生的座位为第 \(1\) \(2\) \(\dots\),成绩为 \(s_n\) 的考生的座位为第 \(1\) \(n\) ,成绩为 \(s_{n+1}\) 的考生的座位为第 \(2\) \(n\) \(\dots\),成绩为 \(s_{2n}\) 的考生的座位为第 \(2\) \(1\) ,成绩为 \(s_{2n+1}\) 的考生的座位为第 \(3\) \(1\) ,以此类推。

例如,若 \(n = 4, m = 5\),则所有 \(4 \times 5 = 20\) 名考生将按照 CSP-J 2025 第一轮成绩从高到低的顺序,根据下图中的箭头顺序分配座位。

给定小 R 所在的考场座位的行数 \(n\)列数 \(m\),以及小 R 所在的考场的所有考生 CSP-J 2025 第一轮的成绩 \(a_1, a_2, \dots, a_{n \times m}\),其中 \(a_1\) 为小 R CSP-J 2025 第一轮的成绩,你需要帮助小 R 求出,他的座位为第几第几

【输入】

输入的第一行包含两个正整数 \(n, m\),分别表示小 R 所在的考场座位的行数列数

输入的第二行包含 \(n \times m\) 个正整数 \(a_1, a_2, \dots, a_{n \times m}\),分别表示小 R 所在的考场的所有考生 CSP-J 2025 第一轮的成绩,其中 \(a_1\) 为小 R CSP-J 2025 第一轮的成绩。

【输出】

输出一行两个正整数 \(c, r\),表示小 R 的座位为第 \(c\) \(r\)

【输入样例】

2 2
99 100 97 98

【输出样例】

1 2

【核心思想】

  1. 问题分析:给定 \(n\)\(m\) 列的考场,\(n \times m\) 个互不相同的成绩按从高到低蛇形填充座位。已知小 R 的成绩 \(a_1\),求他的座位(列,行)。本质上是排序 + 蛇形矩阵定位问题:先对所有成绩降序排序,然后按蛇形规则填充矩阵,找到 \(a_1\) 对应的位置。

  2. 算法选择

    • 降序排序sort(a+1, a+1+n*m, cmp) 将成绩从高到低排列
    • 蛇形填充模拟:按列优先、奇数列向下、偶数列向上的规则填充矩阵
  3. 关键步骤

    • 读取数据:读入 \(n, m\)\(n \times m\) 个成绩,记录 \(k = a[1]\)(小 R 的成绩)
    • 降序排序sort(a+1, a+1+n*m, cmp)
    • 蛇形填充\(i = 1\)\(n \times m\)):
      • \(b[r][c] = a[i]\)
      • \(a[i] = k\),输出 \((c, r)\) 并结束
      • 移动规则
        • \(c\) 为奇数且 \(r = n\)\(c \leftarrow c + 1\)(奇数列到底,右移)
        • \(c\) 为偶数且 \(r = 1\)\(c \leftarrow c + 1\)(偶数列到顶,右移)
        • \(c\) 为奇数:\(r \leftarrow r + 1\)(奇数列向下)
        • \(c\) 为偶数:\(r \leftarrow r - 1\)(偶数列向上)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n \cdot m \cdot \log(n \cdot m))\),排序主导
    • 空间复杂度:\(O(n \cdot m)\),存储矩阵
  5. 蛇形矩阵的核心思想

    • 列优先的蛇形:与常见的行优先蛇形不同,本题按列填充,奇数列从上往下,偶数列从下往上
    • 边界转向:每列填满后转向下一列,转向条件由当前列的奇偶性和当前行位置共同决定
    • 直接模拟的简洁性\(n, m \leq 10\)(由数组大小推断),直接模拟填充过程即可,无需数学公式推导位置
    • 排序后的确定性:成绩互不相同保证排序后每个成绩的位置唯一确定
    • 适用于矩阵填充、排序定位、模拟遍历类问题

【算法标签】

普及- #其他排序

【代码详解】

#include <bits/stdc++.h>
using namespace std;

// 蛇形填充规则:
// 1. 如果列数为奇数,行数为n,则列+1
// 2. 如果列数为偶数,行数为1,则列+1
// 3. 如果列数为奇数,行+1
// 4. 如果列数为偶数,行-1

int n, m;           // n:行数, m:列数
int a[105];         // 存储所有输入的数字
int b[15][15];      // 蛇形填充后的矩阵
int k;              // 要查找的目标数字

// 比较函数:降序排序
bool cmp(int x, int y)
{
    return x > y;
}

int main()
{
    // 输入行数和列数
    cin >> n >> m;

    // 输入所有数字
    for (int i = 1; i <= n * m; i++)
    {
        cin >> a[i];
    }

    // 记录第一个数字作为目标值
    k = a[1];

    // 对所有数字进行降序排序
    sort(a + 1, a + 1 + n * m, cmp);

    // 初始化当前位置(从左上角开始)
    int r = 1, c = 1;  // r:行, c:列

    // 蛇形填充矩阵并查找目标数字的位置
    for (int i = 1; i <= n * m; i++)
    {
        // 将当前数字放入矩阵
        b[r][c] = a[i];

        // 如果找到目标数字,输出其位置(列,行)
        if (a[i] == k)
        {
            cout << c << " " << r << endl;
            return 0;
        }

        // 根据蛇形填充规则移动到下一个位置

        // 情况1:当前列为奇数且到达最后一行,向右移动到下一列
        if (c % 2 && r == n)
        {
            c++;
        }
        // 情况2:当前列为偶数且到达第一行,向右移动到下一列
        else if (c % 2 == 0 && r == 1)
        {
            c++;
        }
        // 情况3:当前列为奇数,向下移动一行
        else if (c % 2)
        {
            r++;
        }
        // 情况4:当前列为偶数,向上移动一行
        else
        {
            r--;
        }
    }

    return 0;
}

【运行结果】

2 2
99 100 97 98

【算法真传】

从一道 CSP-J 真题出发:聊聊蛇形矩阵与排序定位

posted @ 2026-08-17 09:45  团爸讲算法  阅读(42)  评论(0)    收藏  举报