题目描述
上课的时候总会有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情。不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下来之后,只有有限的D对同学上课时会交头接耳。
同学们在教室中坐成了MMM行NNN列,坐在第i行第j列的同学的位置是(i,j)(i,j)(i,j),为了方便同学们进出,在教室中设置了KKK条横向的通道,LLL条纵向的通道。
于是,聪明的小雪想到了一个办法,或许可以减少上课时学生交头接耳的问题:她打算重新摆放桌椅,改变同学们桌椅间通道的位置,因为如果一条通道隔开了222个会交头接耳的同学,那么他们就不会交头接耳了。
请你帮忙给小雪编写一个程序,给出最好的通道划分方案。在该方案下,上课时交头接耳的学生的对数最少。
输入格式
第一行,有555个用空格隔开的整数,分别是M,N,K,L,D(2≤N,M≤1000,0≤K<M,0≤L<N,D≤2000)M,N,K,L,D(2 \le N,M \le 1000,0 \le K<M,0 \le L<N,D \le 2000)M,N,K,L,D(2≤N,M≤1000,0≤K<M,0≤L<N,D≤2000)
接下来的DDD行,每行有444个用空格隔开的整数。第iii行的444个整数Xi,Yi,Pi,QiX_i,Y_i,P_i,Q_iXi,Yi,Pi,Qi,表示坐在位置(Xi,Yi)(X_i,Y_i)(Xi,Yi)与(Pi,Qi)(P_i,Q_i)(Pi,Qi)的两个同学会交头接耳(输入保证他们前后相邻或者左右相邻)。
输入数据保证最优方案的唯一性。
输出格式
共两行。
第一行包含KKK个整数a1,a2,…,aKa_1,a_2,…,a_Ka1,a2,…,aK,表示第a1a_1a1行和a1+1a_1+1a1+1行之间、第a2a_2a2行和a2+1a_2+1a2+1行之间、…、第aKa_KaK行和第aK+1a_K+1aK+1行之间要开辟通道,其中ai<ai+1a_i< a_i+1ai<ai+1,每两个整数之间用空格隔开(行尾没有空格)。
第二行包含LLL个整数b1,b2,…,bLb_1,b_2,…,b_Lb1,b2,…,bL,表示第b1b_1b1列和b1+1b_1+1b1+1列之间、第b2b_2b2列和b2+1b_2+1b2+1列之间、…、第bLb_LbL列和第bL+1b_L+1bL+1列之间要开辟通道,其中bi<bi+1b_i< b_i+1bi<bi+1,每两个整数之间用空格隔开(列尾没有空格)。
输入输出样例
输入 #1
4 5 1 2 3 4 2 4 3 2 3 3 3 2 5 2 4
输出 #1
2 2 4
基本思路:
又是最优解问题啊,这里很显然采用的是贪心的算法。
问题的本质在于求解求解出现频率为前k个元素。
这里有两类做法,我稍微提一下:
- 使用unordered_map存储出现频率,用priority_queue讲遍历的元素存进来(注意利用pair的字典序),对元素的输出顺序也有要求可以再考虑加一个vector或者priority_queue。
- 使用计数排序。每次找到一个最大值就把相应桶的值清零。这样循环做k次就可以得到前k个最大的元素。至于最后的顺序输出可以再次利用桶的思想。
AC代码:
(只提供法1的版本,法2的自行看luogu题解)
#include<bits/stdc++.h>
using namespace std;
int main() {
int m, n;
int k, l;
int d;
cin >> m >> n >> k >> l >> d;
unordered_map<int ,int> row_map, col_map;
for (int i = 0; i < d; ++i) {
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
if (x1 == x2) {
int y = (y1 < y2)? y1 : y2;
++col_map[y];
}
if (y1 == y2) {
int x = (x1 < x2)? x1 : x2;
++row_map[x];
}
}
// 由于pair<int, int>大小是按照字典序来的
// 所以我这里采用 first记录出现次数, second记录单词
priority_queue<pair<int, int>> row, col;
for (auto i = row_map.begin(); i != row_map.end(); ++i) {
row.emplace(i->second, i->first);
}
for (auto i = col_map.begin(); i != col_map.end(); ++i) {
col.emplace(i->second, i->first);
}
// 按照次序打印
priority_queue<int, vector<int>, greater<int>> r, c;
for (int i = 1; i <= k; ++i) {
r.push(row.top().second);
row.pop();
}
for (int i = 1; i <= k; ++i) {
cout << r.top() << " ";
r.pop();
}
cout << endl;
for (int i = 1; i <= l; ++i) {
c.push(col.top().second);
col.pop();
}
for (int i = 1; i <= l; ++i) {
cout << c.top() << " ";
c.pop();
}
cout << endl;
return 0;
}