点击打开链接
下面再介绍STL中与堆相关的4个函数——建立堆make_heap(),在堆中添加数据push_heap(),在堆中删除数据pop_heap()和堆排序sort_heap():
头文件 #include <algorithm>
下面的_First与_Last为可以随机访问的迭代器(指针),_Comp为比较函数(仿函数),其规则——如果函数的第一个参数小于第二个参数应返回true,否则返回false。
建立堆
make_heap(_First, _Last, _Comp)
默认是建立最大堆的。对int类型,可以在第三个参数传入greater<int>()得到最小堆。
在堆中添加数据 ///只对最后一个元素进行堆 排序 所以加数据要在最后一位加
push_heap (_First, _Last)
要先在容器中加入数据,再调用push_heap ()
在堆中删除数据 /// 栈顶元素与最后的元素进行了交换(跑到最后去了)
pop_heap(_First, _Last)
要先调用pop_heap()再在容器中删除数据
堆排序
sort_heap(_First, _Last)
排序之后就不再是一个合法的heap了
#include <cstdio> #include <vector> #include <algorithm> #include <functional> using namespace std; void PrintfVectorInt(vector<int> &vet) { for (vector<int>::iterator pos = vet.begin(); pos != vet.end(); pos++) printf("%d ", *pos); putchar('\n'); } int main() { const int MAXN = 20; int a[MAXN]; int i; for (i = 0; i < MAXN; ++i) a[i] = rand() % (MAXN * 2); //动态申请vector 并对vector建堆 vector<int> *pvet = new vector<int>(40); pvet->assign(a, a + MAXN); //建堆 make_heap(pvet->begin(), pvet->end()); PrintfVectorInt(*pvet); //加入新数据 先在容器中加入,再调用push_heap() pvet->push_back(25); push_heap(pvet->begin(), pvet->end()); PrintfVectorInt(*pvet); //删除数据 要先调用pop_heap(),再在容器中删除 pop_heap(pvet->begin(), pvet->end()); pvet->pop_back(); pop_heap(pvet->begin(), pvet->end()); pvet->pop_back(); PrintfVectorInt(*pvet); //堆排序 sort_heap(pvet->begin(), pvet->end()); PrintfVectorInt(*pvet); delete pvet; return 0; }
题意:给你m个数字集合 每个数字集合中有n个数字
从m个串中挑选一个数字加起来,共有n^m 中相加的方法
求按非降序的顺序输出前n个最小的和
思路:
利用堆的思想将求从m 个数字集合中挑选m 个数字相加
这个m个数相加的过程一步一步的进行
让现有的和与堆中的和进行比较,判断是否更改堆顶;
{
先让堆中的元素随意加入第i个数字 (以加入第一个为例)
然后让现在的堆顶 与 加入其他数字进行比较,判断是否需要更改
}
步骤:
利用两个数组和一个堆进行做
1 a[]表示在添加第i个数字前 的前n个小的和
{即输入第i个串之前 的和}
2 b[]表示当前输的第i串中的数字
3 heap[]表示堆储存
4
[1]
先将第一组串作为堆的基础(a[]有序的)
[2]
输入下一组串b (排序)
然后让堆中的每个数字都加上b[1];
接着让堆顶(为堆中最大数字)与 a[1...n]+b[2...n],进行比较
{
大于
就更新堆顶数字
小于
退出 (有优化的过程(因为提前对a[],b[]都排序了);
}
重复[2] 直到输入了m行
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <vector> #include <queue> #include <algorithm> using namespace std; int heap[3000],a[3000],b[3000]; void adjust(int ind,int len) { int lch=ind<<1; int rch=ind<<1|1; int Max=ind; if(ind<=len/2) { if(lch<=len&&heap[lch]>heap[Max]) Max=lch; if(rch<=len&&heap[rch]>heap[Max]) Max=rch; if(Max!=ind) { swap(heap[Max],heap[ind]); adjust(Max,len); } } } int main() { int T; int n,m; scanf("%d",&T); while(T--) { scanf("%d%d",&m,&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) heap[i]=a[i]; for(int i=n/2;i>=1;i--) adjust(i,n); ///一个数的时候的堆的创建 ///为了使元素满足根大于左右孩子 for(int i=2;i<=m;i++) { sort(a+1,a+n+1); ///排序 优化if(heap[1]>a[k]+b[j]) for(int j=1;j<=n;j++) scanf("%d",&b[j]); sort(b+1,b+n+1); for(int j=1;j<=n;j++) heap[j]+=b[1]; ///建立拥有i个数字相加和的堆 for(int j=2;j<=n;j++) { for(int k=1;k<=n;k++) { if(heap[1]>a[k]+b[j]) ///堆顶与其他相加和进行比较 { heap[1]=a[k]+b[j]; adjust(1,n); } else break; } } for(int j=1;j<=n;j++) ///用a[]来存 拥有i个数字相加和的前n个最小和 a[j]=heap[j]; } sort(heap+1,heap+1+n); for(int i=1;i<n;i++) printf("%d ",heap[i]); printf("%d\n",heap[n]); } return 0; }
STL 堆 #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <vector> #include <queue> #include <algorithm> using namespace std; int heap[3000],a[3000],b[3000]; int main() { int n,m,T; scanf("%d",&T); while(T--) { scanf("%d%d",&m,&n); for(int i=0;i<n;i++) { scanf("%d",&a[i]); heap[i]=a[i]; } make_heap(heap,heap+n); for(int i=1;i<m;i++) { sort(a,a+n); for(int j=0;j<n;j++) scanf("%d",&b[j]); sort(b,b+n); for(int j=0;j<n;j++) heap[j]+=b[0]; for(int j=1;j<n;j++) { for(int k=0;k<n;k++) { if(heap[0]>a[k]+b[j]) { pop_heap(heap,heap+n); ///堆顶不会消失,移动到了最后 heap[n-1]=a[k]+b[j]; push_heap(heap,heap+n); ///只对最后一个元素进行重新堆排序 } else break; } } for(int j=0;j<n;j++) a[j]=heap[j]; } sort(heap,heap+n); for(int i=0;i<n-1;i++) printf("%d ",heap[i]); printf("%d\n",heap[n-1]); } return 0; }