|
|
## [$P1056$ [$NOIP2008$ 普及组] 排座椅 题解](https://www.luogu.com.cn/problem/P1056)
|
|
|
|
|
|
|
|
|
先想一下算法:因为题目里出现了 **最优解** , **最好的方案** 关键字,所以一定会用 **贪心**。然后从题目给的样例解释可以看到:如果相邻的两行有许多组说话的同学,那么在这两行中间加一条过道是非常划算的;同理,列也是如此。
|
|
|
|
|
|
恍然大悟,只要找出划分哪些相邻的两行和相邻的两列可以隔开的同学最多,此题可解。
|
|
|
|
|
|
接下来是找规律:
|
|
|
|
|
|
- 我们先定义两个数组$x,y$:
|
|
|
- $x[1]$表示如果在第一列与第二列中间划分过道能够分开几组说话的同学,同理,$x[2]$则是第二列与第三列... 直到$x[n-1]$
|
|
|
- $y[1]$表示第一行与第二行,$y[2]$表示第二行与第三行... 直到$y[m-1]$
|
|
|
|
|
|
- 题目输入两个同学的坐标,如果横坐标相同,即这两个同学在一行,那么设两个同学纵坐标分别为$a,b$ 如果$a<b$ 那么$x[a]++$ 否则$x[b]++$(这里一定要特判一下$a$和$b$的大小) 同理 $y$ 数组也如此操作即可。
|
|
|
|
|
|
- 最后$x,y$数组分别扫一遍,然后桶排一下即可。
|
|
|
|
|
|
|
|
|
```cpp {.line-numbers}
|
|
|
#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;
|
|
|
}
|
|
|
``` |