POJ3784 动态中位数(大根堆+小根堆+优先队列)

Posted karshey

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ3784 动态中位数(大根堆+小根堆+优先队列)相关的知识,希望对你有一定的参考价值。

题目要求每当输入到奇数个数字时,输出中位数。
我们可以用优先队列来模拟大小根堆,令大根堆放小的数,小根堆放大的数,并且时刻保持大根堆的size大于等于小根堆的,如:当有7个数字时,大根堆4小根堆3;
这样我们就可以保证每次输入奇数的数字时,大根堆.top是中位数,如:

输入1 2 3 4 5 6 7 
大根堆:4 3 2 1
小根堆:5 6 7
此时输出的大根堆的top就是中位数。
如果再输入一个89,自然都要加入小根堆,于是:
大根堆:4 3 2 1
小根堆:5 6 7 8 9
此时大根堆的size小于小根堆,我们就将小根堆的top放入大根堆,此时:
大根堆:5 4 3 2 1
小根堆:6 7 8 9
这样大根堆的top又是中位数了。

关于用优先队列表示大小根堆:

priority_queue<int,vector<int>,less<int>>;//less表示递减,即从大到小,是大根堆
priority_queue<int,vector<int>,greater<int>>;//greater表示递增,是小根堆

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define pb push_back
#define fi first
#define se second
#define mem(a,x) memset(a,x,sizeof(a));
#define db double 

//大根堆放小的,小根堆放大的 
const int N=1e4+10;
int main()
{
	int t;scanf("%d",&t);
	int cas=0;
	while(t--)
	{
		scanf("%d",&cas);
		int m;scanf("%d",&m);
		
		priority_queue<int,vector<int>,less<int>>max_heap;//less递减是大根堆
		priority_queue<int,vector<int>,greater<int>>min_heap;//greater是小根堆
		
		printf("%d %d\\n",cas,(m+1)/2);
		
		for(int i=1;i<=m;i++)
		{
			
			int tmp;scanf("%d",&tmp);
			//放入 
			if(i==1) max_heap.push(tmp);
			else
			{
				if(tmp<=max_heap.top()) max_heap.push(tmp);
				else min_heap.push(tmp);
			}
			
			if(min_heap.size()+1<max_heap.size())
			{
				int tmp2=max_heap.top();
				max_heap.pop();
				min_heap.push(tmp2);
			} 
			else if(max_heap.size()<min_heap.size())
			{
				int tmp2=min_heap.top();
				min_heap.pop();
				max_heap.push(tmp2);
			}
			if(i%2) 
			{
				printf("%d",max_heap.top());
				if(((i+1)/2)%10==0) printf("\\n");
				else printf(" ");
			}
		}
		if(((m+1)/2)%10!=0)printf("\\n"); 
	}
	return 0; 
}

以上是关于POJ3784 动态中位数(大根堆+小根堆+优先队列)的主要内容,如果未能解决你的问题,请参考以下文章

Running Median POJ - 3784

$Poj3784 Running Median$

poj3784Running Median——堆维护中间值

机试练习08:poj3784——动态堆求解中位数

POJ 3784 Running Median

106. 动态中位数经典 / 对顶堆