题目链接: http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=3401
数据结构实验之排序四:寻找大富翁
Time Limit: 150ms Memory limit: 512K 有疑问?点这里^_^
题目描述
2015胡润全球财富榜调查显示,个人资产在1000万以上的高净值人群达到200万人,假设给出N个人的个人资产值,请你快速找出排前M位的大富翁。
输入
首先输入两个正整数N( N ≤ 10^6)和M(M ≤ 10),其中N为总人数,M为需要找出的大富翁数目,接下来给出N个人的个人资产,以万元为单位,个人资产数字为正整数,数字间以空格分隔。
输出
一行数据,按降序输出资产排前M位的大富翁的个人资产值,数字间以空格分隔,行末不得有多余空格。
示例输入
6 3 12 6 56 23 188 60
示例输出
188 60 56
提示
请用堆排序完成。
没这个提示估计也没几个人会去用堆排吧。。
首先注意到时间卡在150ms而数据量N高达10^6,即使是使用高速的排序时间复杂度再低也会超时,比较容易发现的就是M<=10,所以便想到了在这个方面下功夫,大体的思路便就有了,可以先把人数控制在M人,开辟数组a先记录M人,然后遍历第M+1人到N人,每次记录数组a的最小值(假设为min),如果min小于遍历到的值的话便替换掉 min,直到遍历结束,这样便保证了这M人是N人中资产最高的,然后就完全可以不用堆排了233
代码如下:
- #include <bits/stdc++.h>
- using namespace std;
- int a[15], n, m;
- int cmp(const void *a, const void *b)
- {
- return *(int *)b-*(int *)a;
- }
- int main()
- {
- int k=0;
- scanf("%d %d", &n, &m);
- for(int i=0;i<n;i++)
- {
- int t;
- scanf("%d", &t);
- if(k<m) a[k++]=t;
- else
- {
- int min=a[0], f=0;
- for(int j=1;j<m;j++)
- if(a[j]<min) {min=a[j];f=j;}
- if(min<t) a[f]=t;
- }
- }
- qsort(a,m,sizeof(a[0]),cmp);
- for(int i=0;i<m-1;i++)
- printf("%d ", a[i]);
- printf("%d\n", a[m-1]);
- return 0;
- }
好了,这题完了就开始言归正传到堆吧,堆其实就是一个满二叉树(除最后一层无任何子节点外,每一层上的所有结点都有两个子结点二叉树),结构如下图:
比较容易发现的是如果一个节点下标为i的话,他的左儿子(如果有的话)下标为2*i,右儿子(。。。)下标为2*i+1.
堆可分为最大堆和最小堆两类,最大堆指的是任意的结点的值要比他的两个子节点(。。。)的值大,那么最小堆自然就是要小了,像下面的第一个堆就为最大堆,第二个就为最小堆。
堆的具体实现代码如下(这里以最大堆为例):
- #include <cstdio>
- #include <cstring>
- #include <algorithm>
- using namespace std;
- int a[1000+5], n;
- void siftdown(int i) //向下调整函数,将某个值一层一层向下调整,直到同时大于俩个子结点的值
- {
- int t=i;
- while(2*i<=n)
- {
- if(a[i]<a[2*i])
- t=2*i;
- if(a[t]<a[i*2+1]&&i*2+1<=n)
- t=2*i+1;
- if(t!=i) {swap(a[t],a[i]);i=t;} //交换啊a[i]和max(a[i*2],a[i*2+1])的值,并且更新i,使得能够继续向下调整
- else break; //t没有更新,表明已经大于俩个子结点的值,结束本次循环
- }
- return ;
- }
- void heapcreat()
- {
- for(int i=n/2;i>=1;i--)
- siftdown(i);
- return ;
- }
- void heapsort() //堆排序函数,简单说就是找出每次的最大值放在最后,这样就构成了升序序列
- {
- while(n>=1)
- {
- swap(a[1],a[n]); //将此时的最大值放在a[n]
- n--;
- siftdown(1); //对堆从1进行向下调整,找出此时的最大值
- }
- }
- int main()
- {
- while(~scanf("%d", &n))
- {
- int m=n;
- for(int i=1;i<=n;i++)
- scanf("%d", &a[i]);
- heapcreat();
- heapsort();
- for(int i=1;i<m;i++)
- printf("%d ", a[i]);
- printf("%d\n", a[m]);
- }
- return 0;
- }