POJ 2442 Sequence(stl+优先队列||堆)

淩亂°似流年 2022-06-10 07:29 342阅读 0赞

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. 1
  2. 2 3
  3. 1 2 3
  4. 2 2 3

Sample Output

  1. 3 3 4

题解:

题意:

给n个数列,长度都为m,一共m次让你每次从各个数列中选一个数组相加成新的数列,让你求该数列的前n小的值

思路:

首先将给的第一行的数为初始数,每次求前一行(这里的前一行代表是前面所有行的前n小和)与后一行和的前n小的值,遍历完所有行,最后输出就是结果

优先队列代码,时间耗得比堆的写法要多一点:

  1. #include<algorithm>
  2. #include<iostream>
  3. #include<cstring>
  4. #include<stdio.h>
  5. #include<math.h>
  6. #include<string>
  7. #include<stdio.h>
  8. #include<queue>
  9. #include<stack>
  10. #include<map>
  11. #include<deque>
  12. #define M (t[k].l+t[k].r)/2
  13. #define lson k*2
  14. #define rson k*2+1
  15. #define ll long long
  16. #define INF 100861111;
  17. using namespace std;
  18. int a[2005];//存前几行的前n小和
  19. int b[2005];//存当前行的值
  20. priority_queue<int>q;//相当于一个最大堆
  21. int main()
  22. {
  23. int i,j,k,n,m,t,s,ans;
  24. scanf("%d",&t);
  25. while(t--)
  26. {
  27. scanf("%d%d",&m,&n);
  28. s=0;
  29. for(i=0;i<n;i++)
  30. {
  31. scanf("%d",&a[i]);
  32. }
  33. sort(a,a+n);//排序
  34. for(i=1;i<m;i++)
  35. {
  36. for(j=0;j<n;j++)
  37. {
  38. scanf("%d",&b[j]);
  39. q.push(a[j]+b[0]);//将之前每一项与第一项的加作为初始的前n小项进行更新
  40. }
  41. for(j=1;j<n;j++)//对每一个当前数组值进行遍历更新
  42. {
  43. for(k=0;k<n;k++)//遍历相加所有的前n项
  44. {
  45. int x=a[k]+b[j];
  46. if(x>=q.top())//如果当前和比最大堆堆顶都大就不用加下去了
  47. break;
  48. q.pop();
  49. q.push(x);//更新堆顶
  50. }
  51. }
  52. int ans=n-1;//如果要最小的在前要从后往前插入
  53. while(!q.empty())
  54. {
  55. a[ans]=q.top();
  56. q.pop();
  57. ans--;
  58. }
  59. }
  60. printf("%d",a[0]);
  61. for(i=1;i<n;i++)
  62. printf(" %d",a[i]);
  63. printf("\n");
  64. }
  65. return 0;
  66. }

还有就是用make_heap的做法,会比优先队列快一些。。这个是学别人的,实现原理和上面相同只是用的STL工具不同,就不打代码了

然后补充一点关于这个的小知识:

make_heap(a,a+n)a可以是任何类型的数组,用来建堆,不过如果不是基础类型的话就要重载小于号,基础类型不重载默认为最大堆,a[0]就为堆顶,a[n-1]为末尾

用push_heap(a,a+n)作用就是更新堆

pop_heap(a,a+n)作用是将堆顶移到堆的尾部就是a[n-1]处,其他地方保持堆的形状,这些东西如果不是堆就不能用

  1. #include<algorithm>
  2. #include<iostream>
  3. #include<cstring>
  4. #include<stdio.h>
  5. #include<math.h>
  6. #include<string>
  7. #include<stdio.h>
  8. #include<queue>
  9. #include<stack>
  10. #include<map>
  11. #include<deque>
  12. #define M (t[k].l+t[k].r)/2
  13. #define lson k*2
  14. #define rson k*2+1
  15. #define ll long long
  16. #define INF 100861111;
  17. using namespace std;
  18. int a[2005];
  19. int b[2005];
  20. int tem[2005];
  21. int main()
  22. {
  23. int i,j,k,n,m,t,s,ans;
  24. scanf("%d",&t);
  25. while(t--)
  26. {
  27. scanf("%d%d",&m,&n);
  28. s=0;
  29. for(i=0;i<n;i++)
  30. {
  31. scanf("%d",&a[i]);
  32. }
  33. sort(a,a+n);
  34. for(i=1;i<m;i++)
  35. {
  36. for(j=0;j<n;j++)
  37. {
  38. scanf("%d",&b[j]);
  39. tem[j]=a[j]+b[0];
  40. }
  41. make_heap(tem,tem+n);
  42. for(j=1;j<n;j++)
  43. {
  44. for(k=0;k<n;k++)
  45. {
  46. int x=a[k]+b[j];
  47. if(x>=tem[0])
  48. break;
  49. pop_heap(tem,tem+n);
  50. tem[n-1]=x;
  51. push_heap(tem,tem+n);
  52. }
  53. }
  54. sort(tem,tem+n);
  55. for(j=0;j<n;j++)
  56. a[j]=tem[j];
  57. }
  58. printf("%d",a[0]);
  59. for(i=1;i<n;i++)
  60. printf(" %d",a[i]);
  61. printf("\n");
  62. }
  63. return 0;
  64. }

发表评论

表情:
评论列表 (有 0 条评论,342人围观)

还没有评论,来说两句吧...

相关阅读

    相关 优先队列

    设计一个程序模仿操作系统的进程管理问题,进 程服务按优先级高的先服务,同优先级的先到先服务的管理 原则。设文件task.txt中存放了仿真进程服务请求,其中第 一列是进程任务号