zoukankan      html  css  js  c++  java
  • 【POJ 3784】Running Median【堆】【链表】

    题目大意:

    题目链接:http://poj.org/problem?id=3784
    给出由n个数字组成的的数字串,每当输入奇数个时,输出当前的中位数。


    思路:

    思路一:
    如果我们将这个数列从中位数分开,将比中位数小的数放入大根堆,比中位数大的数放入小根堆,中位数也放入大根堆,那么每次读入时,维护两个堆的情况,保持大根堆的元素不比小根堆的元素少且最多多出一个,那么每次输入为奇数个时,中位数为大根堆的对顶。
    时间复杂度O(nlogn)


    思路二:
    要求中位数,那么就要现将这个数组排序。那么就可以先得到最终的中位数。然后数据保持单调性,将一个数与左右用链表连接,并记录下原来在这个位置的是哪个数字。然后每次删除最后输入的两个数字a,b(保持数字个数为奇数),然后分类讨论:

    1. a>midb>midmid=p[mid].l
    2. a<misb<midmid=p[mid].r
    3. min(a,b)<midmax(a,b)>midmid不变
    4. mid(a,b)=midmax(a,b)>midmid=p[mid].l
    5. max(a,b)=midmid(a,b)<midmid=p[mid].r

    最终倒着输出即可。
    时间复杂度O(nlogn)


    代码:

    对顶堆(手打):

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    int n,m,a,maxn[12001],minn[12001],ans[12001],tot_max,tot_min;
    bool ok;
    
    void up_min(int x)  //小根堆上移操作
    {
        int y=x/2;
        while (y>0&&minn[y]>minn[x])  //能往上
        {
            swap(minn[y],minn[x]);  //上移
            x=y;
            y=x/2;
        }
    }
    
    void up_max(int x)  //大根堆上移操作
    {
        int y=x/2;
        while (y>0&&maxn[y]<maxn[x])
        {
            swap(maxn[y],maxn[x]);
            x=y;
            y=x/2;
        }
    }
    
    void down_min(int x)  //小根堆下移操作
    {
        int y=x*2;
        while ((y<=tot_min&&minn[y]<minn[x])||(y+1<=tot_min&&minn[y+1]<minn[x]))  //能继续下移
        {
            if (minn[y+1]<minn[y]&&y+1<=tot_min) y++;  //求更优解
            swap(minn[x],minn[y]);  //下移
            x=y;
            y=x*2;
        }
    }
    
    void down_max(int x)  //大根堆下移操作
    {
        int y=x*2;
        while ((y<=tot_max&&maxn[y]>maxn[x])||(y+1<=tot_max&&maxn[y+1]>maxn[x]))
        {
            if (maxn[y+1]>maxn[y]&&y+1<=tot_max) y++;
            swap(maxn[x],maxn[y]);
            x=y;
            y=x*2;
        }
    }
    
    void push_max()  //将小根堆的对顶插入大根堆
    {
        int a=minn[1];  //取出
        swap(minn[1],minn[tot_min]);
        minn[tot_min]=0;  
        tot_min--;  //删除
        down_min(1);  //维护
        maxn[++tot_max]=a;  //插入
        up_max(tot_max);  //维护
    }
    
    void push_min()  //将大根堆的对顶插入小根堆
    {
        int a=maxn[1];
        swap(maxn[1],maxn[tot_max]);
        maxn[tot_max]=0;
        tot_max--;
        down_max(1);
        minn[++tot_min]=a;
        up_min(tot_min);
    }
    
    int main()
    {
        scanf("%d",&m);
        for (int l=1;l<=m;l++)
        {
            scanf("%d",&n);
            scanf("%d",&n);
            printf("%d %d\n",l,n/2+1);
            memset(maxn,0,sizeof(maxn));
            memset(ans,0,sizeof(ans));
            memset(minn,0,sizeof(minn));
            tot_max=tot_min=0;  //初始化
            for (int i=1;i<=n;i++)
            {
                scanf("%d",&a);
                if (!tot_max)  //堆内没有元素
                 maxn[++tot_max]=a;
                else if (a>maxn[1])  
                {
                    minn[++tot_min]=a;
                    up_min(tot_min);
                }
                else
                {
                    maxn[++tot_max]=a;
                    up_max(tot_max);
                }
                while (tot_min>tot_max)  //维护两个堆
                {       
                    push_max();
                }
                while (tot_max>tot_min+1)
                {
                    push_min();
                }
                if (i%2)  //记录答案
                {
                    ans[i/2+1]=maxn[1];
                }
            }
            ok=true;
            for (int i=1;i<=n/2+1;i++)
            {
                if (i%10==1&&i!=1) 
                {
                    printf("\n");
                    ok=false;
                }
                else ok=true;
                printf("%d ",ans[i]);
            }
            if (ok) printf("\n");
        }
        return 0;
    }

    链表:

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    
    int m,n,ans[12001],mid,sum;
    bool ok;
    
    struct node1  //链表
    {
        int l,r,num;
    }p[12001];
    
    struct node2  //每个数字
    {
        int a,num,old;
    }a[12001];
    
    bool cmp(node2 x,node2 y)
    {
        return x.a<y.a;
    }
    
    void find()  //求出一个位置在没有排序之前的位置
    {
        for (int i=1;i<=n;i++)
         a[a[i].old].num=i;
    }
    
    void make()  //建链表
    {
        for (int i=1;i<n;i++)
        {
            p[i].r=i+1;
            p[i+1].l=i;  //将i和i+1连接
            p[i].num=i;  //记录编号
        }
        p[n].num=n; 
    }
    
    void Delete(int x)  //删除节点
    {
        p[p[x].l].r=p[x].r;
        p[p[x].r].l=p[x].l;
    }
    
    void play()  //求答案
    {
        int k=n;
        int one,two=0;
        while (k>0)
        {
            one=a[k--].num;
            two=a[k--].num;  //最后输入的两个数
            if (one<mid&&two<mid)
             mid=p[mid].r;
            else if (one>mid&&two>mid)
             mid=p[mid].l;
            else if ((one==mid&&two>mid)||(two==mid&&one>mid))
             mid=p[mid].l;
            else if ((one==mid&&two<mid)||(two==mid&&one<mid))
             mid=p[mid].r;
            Delete(one);
            Delete(two);  //删除
            ans[++sum]=a[mid].a;  //记录中位数
        }
    }
    
    void print()  //输出
    {
        for (int i=1;i<sum;i++)
        {
            if (i%10==1&&i>1) 
            {
                printf("\n");
                ok=false;
            }
            else ok=true;
            printf("%d ",ans[sum-i]);  //由于是倒着记录的,所以要倒过来
        } 
        printf("\n");
    }
    
    int main()
    {
        scanf("%d",&m);
        for (int l=1;l<=m;l++)
        {
            scanf("%d",&n);
            scanf("%d",&n);
            printf("%d %d\n",l,n/2+1); 
            memset(ans,0,sizeof(ans));
            sum=0;
            for (int i=1;i<=n;i++)
            {
                scanf("%d",&a[i].a);
                a[i].old=i;  //记录以前编号
            } 
            sort(a+1,a+1+n,cmp);  //排序
            mid=n/2+1;
            ans[++sum]=a[mid].a;
            find();
            make();         
            play();
            print();        
        }
        return 0;
    }
  • 相关阅读:
    Entity Framework Core 2.0 新特性
    asp.net core部署时自定义监听端口,提高部署的灵活性
    asp.net core使用jexus部署在linux无法正确 获取远程ip的解决办法
    使用xshell连接服务器,数字键盘无法使用解决办法
    使用Jexus 5.8.2在Centos下部署运行Asp.net core
    【DevOps】DevOps成功的八大炫酷工具
    【Network】Calico, Flannel, Weave and Docker Overlay Network 各种网络模型之间的区别
    【Network】UDP 大包怎么发? MTU怎么设置?
    【Network】高性能 UDP 应该怎么做?
    【Network】golang 容器项目 flannel/UDP相关资料
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998727.html
Copyright © 2011-2022 走看看