You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2.8 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

P1056 [NOIP2008 普及组] 排座椅 题解

先想一下算法:因为题目里出现了 最优解 , 最好的方案 关键字,所以一定会用 贪心。然后从题目给的样例解释可以看到:如果相邻的两行有许多组说话的同学,那么在这两行中间加一条过道是非常划算的;同理,列也是如此。

恍然大悟,只要找出划分哪些相邻的两行和相邻的两列可以隔开的同学最多,此题可解。

接下来是找规律:

  • 我们先定义两个数组x,y:

    • x[1]表示如果在第一列与第二列中间划分过道能够分开几组说话的同学,同理,x[2]则是第二列与第三列... 直到x[n-1]
    • y[1]表示第一行与第二行,y[2]表示第二行与第三行... 直到y[m-1]
  • 题目输入两个同学的坐标,如果横坐标相同,即这两个同学在一行,那么设两个同学纵坐标分别为a,b 如果a<b 那么x[a]++ 否则x[b]++(这里一定要特判一下ab的大小) 同理 y 数组也如此操作即可。

  • 最后x,y数组分别扫一遍,然后桶排一下即可。

#include <bits/stdc++.h>
using namespace std;
const int N = 1010;

int m, n, k, l, d; // m行n列k条横向的通道l条纵向的通道,d对同学交头接耳
int y[N], x[N];    // 横纵坐标数组
int b1[N], b2[N];  // 桶排要用的数组

int main() {
    cin >> m >> n >> k >> l >> d;

    while (d--) {
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        if (x1 == x2)         // 横坐标相等,则记录到个数数组中
            y[min(y1, y2)]++; // 表示隔开这两排的价值
        else
            x[min(x1, x2)]++; // 记得取min即过道与前一个坐标保持一致
    }

    for (int i = 1; i <= k; i++) { // 循环k次
        int mx = 0;                // 临时最大值
        int p;                     // 临时最大值位置
        for (int j = 1; j <= m; j++) {
            if (x[j] > mx) {
                mx = x[j];
                p = j;
            }
        }
        x[p] = 0; // 求出max之后一定要记得清零否则无论排多少次都是一个答案
        b1[p]++;  // p这行是需要加入过道的
    }

    for (int i = 1; i <= l; i++) {
        int mx = 0;
        int p;
        for (int j = 1; j <= n; j++) {
            if (y[j] > mx) {
                mx = y[j];
                p = j;
            }
        }
        y[p] = 0; // 同上
        b2[p]++;  // p这列是需要加入过道的
    }

    // 输出答案
    for (int i = 1; i <= m; i++)
        if (b1[i]) printf("%d ", i); // 表示需要隔开这行

    puts("");

    for (int i = 1; i <= n; i++)
        if (b2[i]) printf("%d ", i);
    return 0;
}