題目描述
上課的時候總會有一些同學和前後左右的人交頭接耳,這是令小學班主任十分頭疼的一件事情。不過,班主任小雪發現了一些有趣的現象,當同學們的座次確定下來之後,只有有限的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;
}