POJ 2442 Sequence 堆的思想的应用 STL 堆学习

点击打开链接


下面再介绍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;
}



你可能感兴趣的:(POJ 2442 Sequence 堆的思想的应用 STL 堆学习)