• codevs 1245 最小的N个和


    1245 最小的N个和

    题目描述 Description

    有两个长度为 N 的序列 A 和 B,在 A 和 B 中各任取一个数可以得到 N^2 个和,求这N^2 个和中最小的 N个。

    输入描述 Input Description

    第一行输入一个正整数N;第二行N个整数Ai 且Ai≤10^9;第三行N个整数Bi,
    且Bi≤10^9

    输出描述 Output Description

    输出仅一行,包含 n 个整数,从小到大输出这 N个最小的和,相邻数字之间用
    空格隔开。

    样例输入 Sample Input

    5

    1 3 2 4 5 
    6 3 4 1 7

    样例输出 Sample Output

    2 3 4 4 5

    数据范围及提示 Data Size & Hint

    【数据规模】 对于 100%的数据,满足 1≤N≤100000。

    堆的基本操作+贪心

    堆的基本操作讲解,见随笔:讲解——堆http://www.cnblogs.com/TheRoadToTheGold/p/6238795.html

    设输入数据存在数组a[]和b[]中,heap[]为大根堆

    为什么题目要求最小的n个,我们却要维护大根堆呢?看完以下几个步骤再说。

    1、排序:题目要求输出最小的n个数,所以先将两个数组从小到大排序

    2、heap[]初始化:因为固定输出n个数,所以把排序之后的数组a[1]依次与b[]的每一个数相加,和加入heap[]中

    3、从a[2]开始枚举每一个数,如果a中的第i个+b中的第1个(即b中最小的一个)>=heap[1](即堆中最大的元素),那么结束枚举。因为a是递增的,b也是递增的,后面的相加的和会更大。

        如果a中第i个+b中第j个>=heap[1],那么枚举a的下一个,因为b中元素递增,与同一个a相加后更大;枚举a的下一个,b从第一个开始,可能会产生更小的。

    4、步骤3中,在每加入一个元素之前,都要删除堆中第一个(即最大的),因为加入的元素一定小于堆中第一个元素。

    5、取出堆中的每一个元素,因为是大根堆,而题目要最小的n个,所以倒叙存储。

    6、输出答案

    由此可见为什么要维护大根堆了吧!利用大根堆的第一个元素可以快速判断a,b中的数还有没有枚举的必要。

    有人可能说了,那我维护一个小根堆,不是也能判断吗?

    的确,也能判断。

    但小根堆中最大的元素查找时间复杂度为o(n/2),大根堆为O(1)。当然是大根堆快啦。

    此处容易有一个理解偏差:认为小根堆中最大的元素就是heap[n],实际不是这样:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,a[100001],b[100001],heap[100010],s,ans[100001];//s表示heap[]中的元素个数
    int init()//读入优化 
    {
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    void insert(int k)//往堆中加入元素k 
    {
        s++;
        int p=s;
        heap[s]=k;
        while(p>1&&k>heap[p/2])
        {
            heap[p]=heap[p/2];
            p/=2;
        }
        heap[p]=k;
    }
    void heapify(int t)//维护堆 
    {
        int left=t*2,right=t*2+1;
        int maxn=t;
        if(left<=s) maxn=heap[maxn]>heap[left] ? maxn:left;
        if(right<=s) maxn=heap[maxn]>heap[right] ? maxn:right;
        if(maxn!=t)
        {
            swap(heap[maxn],heap[t]);
            heapify(maxn);
        }
    }
    int get()//取出堆中最大值 
    {
        int top=heap[1];
        heap[1]=heap[s];
        s--;
        heapify(1);
        return top;
    }
    int main()
    {
        n=init();
        for(int i=1;i<=n;i++) a[i]=init();
        for(int i=1;i<=n;i++) b[i]=init();
        sort(a+1,a+n+1);//排序,对应第1步 
        sort(b+1,b+n+1);
        for(int i=1;i<=n;i++) insert(a[1]+b[i]);//堆得初始化,对应第2步 
        for(int i=2;i<=n;i++)//对应第3步 
        {
            if(heap[1]<=a[i]+b[1]) break;
            for(int j=1;j<=n;j++)
            {
                if(heap[1]<=a[i]+b[j]) break;
                get();//对应第5步 
                insert(a[i]+b[j]);
            }
        }
        while(s) ans[s]=get();//对应第6步 
        for(int i=1;i<=n;i++) printf("%d ",ans[i]);//对应第7步 
    }

    刚开始超时一个点,原因是两个判断break的语句没有加等号。只想着相等的元素也要输出,却忽略了判断的是堆中最大的元素,相不相等无所谓。

    超时的数据:n=10000,然后20000个1,所有的和都是2

  • 相关阅读:
    fla使用as文件
    软件测试职业发展之路的反思(转)
    java 关键字
    卖空大师”:中国经济构造畸形 坚决卖空中国
    Cumulative Update package 3 for SQL Server 2008 R2
    tt
    javadoc
    as3程序主类,执行顺序
    AS3 (25) 处理声音
    10个励志小故事
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6239034.html
Copyright © 2020-2023  润新知