题目
题目描述: 对于此问题,您将编写一个程序来读取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; } //函数区