zoukankan      html  css  js  c++  java
  • POJ 3784 Running Median (动态中位数)

    题目链接:http://poj.org/problem?id=3784

    题目大意:依次输入n个数,每当输入奇数个数的时候,求出当前序列的中位数(排好序的中位数)。

      此题可用各种方法求解。

      排序二叉树方法,每个结点保存以其为根的左右子树中数的个数。如果数据出的够严格,这种方法会被卡的,除非是通过动态调整维持树的高度较小。

      排序二叉树的代码如下:

    #include <cstdio>
    using namespace std;
    #define N 20000
    
    struct Node {
        int v;
        Node *lc, *rc;//左子树、右子树
        int ln, rn;//左右子树下保存数的个数
    };
    
    Node* Tr;//树根
    
    
    void insert(Node *&T, int v)//注意T要引用
    {
        if(T==NULL)
        {
            T = new Node();
            T->v = v;
            T->lc = T->rc = NULL;
            T->ln = T->rn = 0;
            return;
        }
        if(v <= T->v)
        {
            insert(T->lc, v);
            T->ln++;
        }
        else
        {
            insert(T->rc, v);
            T->rn++;
        }
    }
    
    int query(Node *T, int c)
    {
        int num = T->ln;
        if(c == num+1) return T->v;
        if(c < num+1) return query(T->lc, c);
        else return query(T->rc, c-num-1);
    }
    
    int ans[N];
    int main()
    {
        int T, cas, n, v;
        scanf("%d", &T);
        while(T--)
        {
            int c = 0;
            Tr = NULL;
            scanf("%d %d", &cas, &n);
            for(int i = 0; i < n; i++)
            {
                scanf("%d", &v);
                insert(Tr, v);
                if(i % 2 == 0) ans[c++] = query(Tr, (i+2)/2);
            }
    
            printf("%d %d
    ", cas, (n+1)/2);
            printf("%d",ans[0]);
            for(int i = 1; i < c; i++)
            {
                if(i%10==0)puts("");
                else printf(" ");
                printf("%d", ans[i]);
            }
            if(c % 10 != 0) puts("");
        }
        return 0;
    }
    View Code

      堆方法,维护两个堆,一个大顶堆,一个小顶堆,大顶堆保存较小的一半数,小顶堆保存较大的一半数,任何时刻,任何时刻,保证大顶堆中元素的个数比小顶堆中的元素个数多1或相等,则大顶堆的堆顶元素就是中位数,代码如下:

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    #define N 20000
    
    int smaq[N], bigq[N];
    
    bool cmp(int a, int b){
        return a > b;
    }
    
    int ans[N];
    int main()
    {
        int T, cas, n, v;
        scanf("%d", &T);
        while(T--)
        {
            int c = 0;
            scanf("%d %d", &cas, &n);
            int t1 = 0, t2 = 0;
            for(int i = 0; i < n; i++)
            {
                scanf("%d", &v);
                if(t1 == 0 || bigq[0] >= v) bigq[t1++] = v;
                else smaq[t2++] = v;
                push_heap(bigq, bigq+t1);
                push_heap(smaq, smaq+t2, cmp);
                
                if(t1-t2 == 2)
                {
                    pop_heap(bigq, bigq+t1);
                    smaq[t2++] = bigq[--t1];
                    push_heap(smaq, smaq+t2, cmp);
                }
                else if(t2-t1 == 1)
                {
                    pop_heap(smaq, smaq+t2, cmp);
                    bigq[t1++] = smaq[--t2];
                    push_heap(bigq, bigq+t1);
                }
                if(i % 2 == 0) ans[c++] = bigq[0];
            }
            printf("%d %d
    ", cas, (n+1)/2);
            printf("%d",ans[0]);
            for(int i = 1; i < c; i++)
            {
                if(i%10==0)puts("");
                else printf(" ");
                printf("%d", ans[i]);
            }
            if(c % 10 != 0) puts("");
        }
        return 0;
    }
    View Code

      线段树方法,先将所有数据读入,做离散化,这样,每个数插入的时候直接插入到其应该去的位置上(排好序的下标),就可以用线段树了。

    #include <cstdio>
    #include <algorithm> 
    #include <cstring>
    using namespace std;
    #define N 20000
    
    int tr[N<<2];//线段树 
    
    void insert(int id, int l, int r, int pos)//在一个位置插入 
    {
        tr[id]++;
        if(l == r) return ;
        int lc = id<<1, rc = (id<<1)|1, mid = (l+r)>>1;
        if(pos <= mid) insert(lc, l, mid, pos);
        else insert(rc, mid+1, r, pos);
    }
    
    int query(int id, int l, int r, int c)//查询第c个数 
    {
        if(l == r) return l;
        int lc = id<<1, rc = (id<<1)|1, mid = (l+r)>>1;
        if(tr[lc] >= c) return query(lc, l, mid, c);
        else return query(rc, mid+1, r, c-tr[lc]);
    }
    
    int ans[N];
    int sq[N], sortsq[N];
    
    
    int find(int l, int r, int v)
    {
        while(l <= r)
        {
            int mid = (l+r)>>1;
            if(v == sortsq[mid]) return mid;
            else if(v < sortsq[mid]) r = mid-1;
            else l = mid+1;
        }
    }
    
    int main()
    {
        int T, cas, n, v;
        scanf("%d", &T);
        while(T--)
        {
            memset(tr, 0, sizeof(tr)); 
            int c = 0;
            scanf("%d %d", &cas, &n);
            for(int i = 0; i < n; i++) scanf("%d", &sq[i]);
            memcpy(sortsq, sq, sizeof(sq));
            sort(sortsq, sortsq+n);
            //for(int i = 0; i < n; i++) printf("%d ", sortsq[i]); puts(""); 
                
            for(int i = 0; i < n; i++)
            {
                int id = find(0, n-1, sq[i]);
                insert(1, 0, n-1, id);
                if(i%2 == 0) 
                //printf("id = %d
    ", query(1, 0, n-1, (i+2)/2));
                ans[c++] = sortsq[query(1, 0, n-1, (i+2)/2)];
            }
            //for(int i = 1; i <= 2*n; i++)printf("%d ", tr[i]); puts("");
            printf("%d %d
    ", cas, (n+1)/2);
            printf("%d",ans[0]);
            for(int i = 1; i < c; i++)
            {
                if(i%10==0)puts("");
                else printf(" ");
                printf("%d", ans[i]);
            }
            if(c % 10 != 0) puts("");
            
        }
        return 0;
    }
    View Code
  • 相关阅读:
    测试开发题目整理(二)
    测试开发题目整理(一)
    Python + request接口测试中Cookie和Session的获取和使用
    requests发送HTTPS请求(处理SSL证书验证)
    js ES5面向对象继承 模仿ES6
    如何使用canvas绘制椭圆,扩展非chrome浏览器中的ellipse方法
    javascript对象创建及继承
    观察者模式及事件与委托的区别-20171215内训会
    html5悬浮球效果
    文本框高度自适应不出滚动条
  • 原文地址:https://www.cnblogs.com/beisong/p/4653818.html
Copyright © 2011-2022 走看看