题目
题目描述: 对于此问题,您将编写一个程序来读取32位带符号整数的序列。读取每个奇数索引值后,输出到目前为止接收到的元素的中位数。
输入的第一行包含一个整数(1≤P≤1000),它是随后的数据集的数量。
每个数据集的第一行包含数据集编号,后跟一个空格,后跟一个奇数十进制整数M(1≤M≤9999),给出要处理的有符号整数的总数。
数据集中的剩余行由值组成,每行10个值,以单个空格分隔。
数据集中的最后一行可能包含少于10个值。
对于每个数据集,输出的第一行包含数据集编号,一个空格和中位数的数量(应为输入值数量的一半加一)。
输出中位数将在以下几行中,每行10个,中间用一个空格隔开。
最后一行可能少于10个元素,但至少有1个元素。输出中不应有空行。
解析
这道题不难,我们只要知道中位数就好了。
- 我们就会想到二叉排序树的根节点在一定条件下就是中位数,我们可以用平衡二叉树来写(这个我不会)。
所以我们用堆(优先队列来模拟类似过程):
- 平衡二叉树的思想就是在新节点进来的时候保持树的平衡。而我们这里用两个堆,一个大根堆一个小根堆(保持他俩平衡)。
- 保持平衡有什么用呢?当两个堆的总节点数为奇数时,较多节点的堆顶就是中位数(因为大根堆存了较小的一半,小根堆存了较大的一半,栈顶正好为中间的元素)。
堆思想我们已经懂了,然后是操作:
- 我们怎么对两个堆进行操作呢?我们首先将一个元素进任意堆,然后以该元素作为中值,判断接下来的数据要进的堆。
- 我们假设第一个元素在小根堆。然后在入堆的过程中,比较元素与堆顶的大小,小就入大根堆,大就入小根堆(保证堆顶是中值)。
- 要注意不能先全部进一个堆再平衡!(只有我会)因为单独入一遍会导致堆的顺序错乱。
比如9,8,7,我们首先当然是9,但如果单进一边,第二个就是7。一个比8小的数却在小根堆占据了中值的位置。 - 最后每逢奇数就输出中值!!!(这里我看题目都没看出来是这个意思)
打代码咯:
- 输入题目给定数据。
- 入堆操作,堆平衡操作,遇到奇数就把中位数存到数组里面。
- 最后输出的时候注意一下格式就好了,每十个就要换一次行(如果最后一行正好十个不换)。
AC代码
#include <iostream>
#include <queue>
using namespace std;
//代码预处理区
const int MAX = 1e6 + 7;
priority_queue<int, vector<int>, greater<int> > mn;//小顶堆
priority_queue<int, vector<int>, less<int> > mx;//大顶堆
int ans[MAX];
//全局变量区
template<class T>inline void read(T& res);
//函数预定义区
int main() {
int T; read(T);
while (T--) {
while (!mn.empty()) mn.pop();
while (!mx.empty()) mx.pop();
int n, m; read(n); read(m);
for (int i = 1; i <= m; i++) {
int x; read(x);
if (1 == i) mn.push(x);
else
if (x > mn.top()) mn.push(x);
else mx.push(x);
int size_mn = mn.size();
int size_mx = mx.size();
if (size_mn - size_mx > 1) {
mx.push(mn.top()); mn.pop();
}
else if (size_mx - size_mn > 1) {
mn.push(mx.top()); mx.pop();
}
//堆转移
if (i & 1)
if (mn.size() > mx.size()) ans[i / 2 + 1] = mn.top();
else ans[i / 2 + 1] = mx.top();
}
m = m / 2 + 1;
printf("%d %d\n", n, m);
for (int i = 1; i <= m; i++) {
printf("%d ", ans[i]);
if (i < m && 0 == i % 10) printf("\n");
}
printf("\n");
}
return 0;
}
template<class T>inline void read(T& res) {
char c; T flag = 1;
while ((c = getchar()) < '0' || c > '9')
if (c == '-')
flag = -1;
res = c - '0';
while ((c = getchar()) >= '0' && c <= '9')
res = res * 10 + c - '0';
res *= flag;
}
//函数区
京公网安备 11010502036488号