POj-3784 Running Median-对顶堆

版权声明:欢迎转载 https://blog.csdn.net/suntengnb/article/details/80027441

问题描述:
For this problem, you will write a program that reads in a sequence of 32-bit signed integers. After each odd-indexed value is read, output the median (middle value) of the elements received so far.
题目大意:
给出一个序列,输出其子序列 [1,2i1]2i1n 的中位数
AC代码:

int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        priority_queue<int,vector<int>,less<int> > pq1;//大顶堆
        priority_queue<int,vector<int>,greater<int> > pq2;//小顶堆
        int id,n;
        cin >> id >> n;
        printf("%d %d\n",id,n / 2 + 1);//中位数的总数
        int cnt = 0;//每输出10个数换行一次
        for(int i = 1; i <= n; ++i)
        {
            int t;
            cin >> t;
            if(i % 2 == 1)//如果是第奇数个数
            {
                pq2.push(t);//加入小顶堆
                while(!pq1.empty() && pq1.top() > pq2.top())//维护对顶堆的性质,注意第一次大顶堆为空
                {
                    //交换堆顶元素
                    int t1 = pq1.top();
                    pq1.pop();
                    int t2 = pq2.top();
                    pq2.pop();
                    pq1.push(t2);
                    pq2.push(t1);
                }
                printf("%d ",pq2.top());//输出小顶堆对顶
                cnt++;
                if(cnt % 10 == 0)
                    cout << endl;
            }
            else//第偶数个数放入大顶度
                pq1.push(t);
        }
        cout << endl;
    }
    return 0;
}

解决方法:
对于一个序列中的中位数,它左边的数都比它小,右边的数都比它大。比较暴力的想法是对每一个要求的序列都进行一次快排,输出中间的数。这样非常地慢,而且信息过多(升序)是一种浪费,对于左边的数,只要比中位数小就可以了,没必要有序。
根据数学中的如果一个集合A中最小的数比另一个集合B中最大的数大,则A中的所有数大于B中的所有数。
集合中的最大最小数容易让我们联想到堆这种数据结构
最小堆的堆顶要大于最大堆的堆顶,而如果最小堆的大小比最大堆的大小多1的话,最小堆的堆顶就是中位数!
最小堆与最大堆之间的关系在中位数的输出之前维护即可

猜你喜欢

转载自blog.csdn.net/suntengnb/article/details/80027441
今日推荐