[ACM] POJ 2442 Sequence (堆的性质)

Sequence

Time Limit: 6000MS   Memory Limit: 65536K
Total Submissions: 7011   Accepted: 2262

Description

Given m sequences, each contains n non-negative integer. Now we may select one number from each sequence to form a sequence with m integers. It‘s clear that we may get n ^ m this kind of sequences. Then we can calculate the sum
of numbers in each sequence, and get n ^ m values. What we need is the smallest n sums. Could you help us?

Input

The first line is an integer T, which shows the number of test cases, and then T test cases follow. The first line of each case contains two integers m, n (0 < m <= 100, 0 < n <= 2000). The following m lines indicate the m sequence
respectively. No integer in the sequence is greater than 10000.

Output

For each test case, print a line with the smallest n sums in increasing order, which is separated by a space.

Sample Input

1
2 3
1 2 3
2 2 3

Sample Output

3 3 4

Source

POJ Monthly,Guang Lin

解题思路:

有m行,每行n个数,从每行中取出一个数相加一起求出sum,这样的sum有n的m次方个。要求的前n个最小的sum值。

第一次使用STL里面的堆,一开始对pop_heap()有点不太理解,后来明白了,比如对数组heap[n],最大下标为n-1建堆,默认的是建立大顶堆,heap[0]是数组中最大的数,写一条pop_heap()语句,就是把heap[0]和
heap[n-1]互换,然后重新对 heap[0]到heap[n-2] (除去最后一个元素)重新建堆,heap[0]依然是最大值,这样相当于更新最大值的操作。

对于本题,堆的性质可以很好的运用。 三个数组old[n] , new [n] , heap[n],old[]是用来保存前i行元素每行取出一个元素加起来所得的前n个最小sum,new[n]是第i+1行的输入元素,heap[n]是中间数组,用来建堆,并更新其最大值元素,每处理完第i行,获得前i行的前n个最小sum(这时保存在heap[]里面),就把heap[]元素赋给old[],这样前m行都处理完毕后,再对old[]数组从小到大排一次序,输出即为所求了。

下面具体说一下heap[]的作用。

一开始把第一行的元素赋给old[], 并对其排序,然后将第一行的元素都加上第二行排序后的第一个元素,把n个值放到heap[]里面,这样就获得了一个临时的前两行的前n个sum值,但这并不一定是前两行最小的前n个sum值  ,因为第二行也有n个元素,得枚举出所有情况(即第二行的第二个,第三个...元素分别与第一行的所有值相加获得sum值)要在这些所有的情况里面取最小的前n个,这就要发挥堆的作用了,前面说临时的前n个sum值保存在heap[]里面了,然后对heap[]进行建堆make_heap(heap,heap+n);默认大顶堆,即heap[0]是最大值,在枚举的时候如果有发现求出的一个临时sum值(temp)比heap[
0 ]要小,那就需要对heap[0]更新,因为我们是要求前n个最小的sum值,用 pop_heap(heap,heap+n);把最大值heap[0]与heap[n-1]互换,然后另heap[n-1] = temp;这样heap[]最大值就更新了(原来的最大值从数组中去除),但不知道是数组中的哪一个值,push_heap(heap,heap+n);  对其重新建堆,这样heap里面的最大的就是heap[0] 了。枚举完,更新完就把前两行的前n个最小的sum值求出来了,剩下的行是相同的操作。 上面的排序是为了减少不必要的操作,在枚举时可以提前退出,这就和
排序好的 2,4,5,6我们要最小的值,那就取2,不用考虑后面的数了一样。

代码:

#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=2010;
int Old[maxn],New[maxn],heap[maxn];

int main()
{
    int t;cin>>t;
    int m,n;
    while(t--)
    {
        cin>>m>>n;
        for(int i=0;i<n;i++)
            cin>>Old[i];
        sort(Old,Old+n);
        m--;
        while(m--)
        {
            for(int i=0;i<n;i++)
                cin>>New[i];
            sort(New,New+n);
            for(int i=0;i<n;i++)
                heap[i]=Old[i]+New[0];
            make_heap(heap,heap+n);//建立大顶堆,heap[0]是最大的值

            //通过枚举把heap里面的大值都换掉,每次换的都是当前的最大值
            for(int i=1;i<n;i++)//新数据的剩下的值
            {
                bool ok=0;
                for(int j=0;j<n;j++)//旧数组
                {
                    int temp=New[i]+Old[j];
                    if(temp<heap[0])
                    {
                        pop_heap(heap,heap+n);//heap数组里面的最后一个元素和第一个元素(最大值)互换,并把除最后一个元素以外的元素重新建堆
                        heap[n-1]=temp;
                        push_heap(heap,heap+n);
                        ok=1;//可以更新最大值
                    }
                    else //当旧数组的第j个数和新数组的数第i个数相加已经没有比大值还小的了,就不用再继续加旧数组了,因为旧数组是排好序的,再加也会比heap里面的最大值大
                        break;
                }
                if(!ok)//如果新数据的第i个数分别和旧数组的n个数相加都没有更新heap[]里面的最大值,那么第i+1个数肯定也不会更新,因为排好序
                    break;
            }
            for(int i=0;i<n;i++)
                Old[i]=heap[i];
            sort(Old,Old+n);
        }
        for(int i=0;i<n-1;i++)
            cout<<Old[i]<<" ";
        cout<<Old[n-1]<<endl;
    }
    return 0;
}

下面贴一下堆的知识:http://blog.csdn.net/hnust_xiehonghao/article/details/9172875转载

最大堆最小堆代码实现

http://blog.csdn.net/xiaoxiaoxuewen/article/details/7570621

最大堆 最小堆原理图

http://www.cnblogs.com/wu8685/archive/2010/12/30/1922218.html

STL 的堆操作

http://hi.baidu.com/solofancy/item/14acd02b9743f7d30f37f927

http://blog.csdn.net/morewindows/article/details/6967409

STL 的堆操作  来自上面的博客

STL里面的堆操作一般用到的只有4个:make_heap();、pop_heap();、push_heap();、sort_heap();

他们的头文件函数是#include <algorithm>

首先是make_heap();

他的函数原型是:void make_heap(first_pointer,end_pointer,compare_function);

一个参数是数组或向量的头指针,第二个向量是尾指针。第三个参数是比较函数的名字。在缺省的时候,默认是大跟堆。(下面的参数都一样就不解释了)

作用:把这一段的数组或向量做成一个堆的结构。范围是(first,last)

然后是pop_heap();

它的函数原型是:void pop_heap(first_pointer,end_pointer,compare_function);

作用:pop_heap()不是真的把最大(最小)的元素从堆中弹出来。而是重新排序堆。它

把first和last交换,然后将[first,last-1)的数据再做成一个堆。

接着是push_heap() void pushheap(first_pointer,end_pointer,compare_function);

作用:push_heap()假设由[first,last-1)是一个有效的堆,然后,再把堆中的新元素加

进来,做成一个堆。

最后是sort_heap()void sort_heap(first_pointer,end_pointer,compare_function);

作用是sort_heap对[first,last)中的序列进行排序。它假设这个序列是有效堆。(当然

,经过排序之后就不是一个有效堆了)

实例:

#include<algorithm>
#include<cstdio>
using namespace std;
bool cmp(int a,int b)
{
  return a>b;
}
int main()
{
  int i,number[20]={29,23,20,22,17,15,26,51,19,12,35,40};
  make_heap(&number[0],&number[12]);
  //结果是:51 35 40 23 29 20 26 22 19 12 17 15
  for(i=0;i<12;i++)
    printf("%d ",number[i]);
  printf("\n");
  make_heap(&number[0],&number[12],cmp);
  //结果:12 17 15 19 23 20 26 51 22 29 35 40
  for(i=0;i<12;i++)
    printf("%d ",number[i]);
  printf("\n");
  //加入元素8
  number[12]=8;
  //加入后调整
  push_heap(&number[0],&number[13],cmp);
  //结果:8 17 12 19 23 15 26 51 22 35 40 20
  for(i=0;i<13;i++)
    printf("%d ",number[i]);
  printf("\n");
  //弹出元素8
  pop_heap(&number[0],&number[13],cmp);
  //结果:12 17 15 19 23 20 26 51 22 29 35 40
  for(i=0;i<13;i++)
    printf("%d ",number[i]);
  printf("\n");
  sort_heap(&number[0],&number[12],cmp);
  //结果不用说都知道是有序的了!
  for(i=0;i<12;i++)
    printf("%d ",number[i]);
  return 0;
}

[ACM] POJ 2442 Sequence (堆的性质)

时间: 2024-08-09 17:40:00

[ACM] POJ 2442 Sequence (堆的性质)的相关文章

POJ 2442 Sequence(堆的使用练习)

题目地址:POJ 2442 真心没想到这题的思路..原来是从第一行逐步向下加,每次都只保存前n小的数.顺便练习了下堆..不过感觉堆的这种用法用的不太多啊.. 又是手残..把j写成了i,于是就改啊改..改的跟题解上的几乎一样了= = !.. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #inc

POJ 2442 Sequence【堆】

题目链接:http://poj.org/problem?id=2442 题目大意:给出一个m*n的矩阵,从每一行中取出一个数相加,能得到n^m个不同的结果,要求输出其中前n项. 建立一个以n元数组为底层数组的堆,在这里,利用stl中的make_heap,pop_heap,push_heap等函数解决. 1.将第一组数据输入arr1数组,升序排序. 2.将接下来的数据输入到arr2数组中,并且heap[i]=arr1[0]+arr2[0...n-1],make_heap(heap,heap+n).

poj 2442 Sequence 优先队列的运用

题意: 给m行,每行n个数,从每行取一个数计算和,求前n小的和. 分析: 优先队列的运用,主要是make_heap,pop_heap,push_heap三个STL函数的用法. 代码: //poj 2442 //sep9 #include <iostream> #include <algorithm> using namespace std; const int maxN=2048; int a[maxN],b[maxN],sum[maxN]; int main() { int ca

poj 2442 Sequence

Sequence Time Limit: 6000MS   Memory Limit: 65536K Total Submissions: 7019   Accepted: 2266 题目大意:给出n个序列每一个序列有每一个元素在每一个序列里取出一个元素求和  输出前n个最小和 优先队列 #include<cstring> #include<cstdio> #include<cstring> #include<queue> #include<iostr

[ACM] POJ 1442 Black Box (堆,优先队列)

Black Box Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 7099   Accepted: 2888 Description Our Black Box represents a primitive database. It can save an integer array and has a special i variable. At the initial moment Black Box is empt

【POJ 2442】Sequence

[POJ 2442]Sequence 优先队列 m个序列 每个序列n个数 从每个序列中取一个数 可以组成一个长为m的序列 这样一共有n^m种组法 把所有组合的加和排序后输出前n小的和 乍一看听高深的一个问题 其实想清楚了很简单 每一组中取一个数相加 第一组可以有n种取法 假设当前只有两组 按题意组合就是将第一组中n个数分别与第二组n个数相加 取出前n小的和 那么现在再来一组 前两组一共有n*n种组合 每种组合与第三组中n个数再组合 前n小的和就是结果 这三组一共有n^3种组合 然而答案只需要前n

[ACM] POJ 1141 Brackets Sequence (区间动态规划)

Brackets Sequence Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 25087   Accepted: 7069   Special Judge Description Let us define a regular brackets sequence in the following way: 1. Empty sequence is a regular sequence. 2. If S is a re

[ACM] POJ 2593 Max Sequence (动态规划,最大字段和)

Max Sequence Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 15569   Accepted: 6538 Description Give you N integers a1, a2 ... aN (|ai| <=1000, 1 <= i <= N). You should output S. Input The input will consist of several test cases. Fo

[ACM] POJ 1026 Cipher (组合数学,置换)

Cipher Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 19228   Accepted: 5148 Description Bob and Alice started to use a brand-new encoding scheme. Surprisingly it is not a Public Key Cryptosystem, but their encoding and decoding is base