序列合并求前K小项 POJ2442

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <algorithm>
 5 #include <queue>
 6
 7 using namespace std;
 8
 9 priority_queue<int>pq;
10 int an[3100];
11 int bn[3100];
12
13 int main()
14 {
15     int T;
16     cin>>T;
17     while(T--)
18     {
19         int m,n;
20         scanf("%d%d",&m,&n);
21         for(int i=0;i<n;i++)
22             scanf("%d",&an[i]);
23         for(int i=1;i<m;i++)
24         {
25             for(int t=0;t<n;t++)
26             {
27                 scanf("%d",&bn[t]);
28             }
29             for(int t=0;t<n;t++)
30             {
31                 pq.push(an[0]+bn[t]);
32             }
33             for(int t=1;t<n;t++)
34             {
35                 for(int j=0;j<n;j++)
36                 {
37                     if(an[t]+bn[j]<pq.top())
38                     {
39                         pq.pop();
40                         pq.push(an[t]+bn[j]);
41                     }
42                 }
43             }
44             for(int t=0;t<n;t++)
45             {
46                 an[t]=pq.top();
47                 pq.pop();
48             }
49         }
50         cout<<an[n-1];
51         for(int i=n-2;i>=0;i--)
52             cout<<" "<<an[i];
53         cout<<endl;
54     }
55     return 0;
56 }

解题步骤:

1.将第一序列读入data1向量中,并按升序排序。

2.将数据读入data2向量中,并按升序排序。

将data2[0] + data1[i] ( 0<=i<=n-1)读入dataq向量中

用make_heap对dataq建堆。

然后data2[1] + data1[i] (0<=i<=n-1),如果data2[1] + data1[i]比堆dataq的顶点大,则退出,否则删除

堆的顶点,插入data2[1] + data1[i]。然后是data2[2],...data2[n - 1]

3.将dataq的数据拷贝到data1中,并对data1按升序排序

4.循环2,3步,直到所有数据读入完毕。

5.打印data1中的数据即为结果。

按此方法,每次只需和当前最小的K项中最大的那项比较就行,而不用比较n^m次

时间: 2024-11-09 02:50:45

序列合并求前K小项 POJ2442的相关文章

6041 I Curse Myself(点双联通加集合合并求前K大) 2017多校第一场

题意: 给出一个仙人掌图,然后求他的前K小生成树. 思路: 先给出官方题解 由于图是一个仙人掌,所以显然对于图上的每一个环都需要从环上取出一条边删掉.所以问题就变为有 M 个集合,每个集合里面都有一堆数字,要从每个集合中选择一个恰好一个数加起来.求所有的这样的和中,前 K 大的是哪些.这就是一个经典问题了. 点双联通就不说了 都一眼能看出来做法就是缩点之后每个环每次取一个,然后找最大的k个所以这道题的难点就在这里,做法当然是不知道啦,看了题解和博客才懂的.以前做过两个集合合并的,这个是k个合并,

算法导论学习之线性时间求第k小元素+堆思想求前k大元素

对于曾经,假设要我求第k小元素.或者是求前k大元素,我可能会将元素先排序,然后就直接求出来了,可是如今有了更好的思路. 一.线性时间内求第k小元素 这个算法又是一个基于分治思想的算法. 其详细的分治思路例如以下: 1.分解:将A[p,r]分解成A[p,q-1]和A[q+1,r]两部分.使得A[p,q-1]都小于A[q],A[q+1,r]都不小于A[q]; 2.求解:假设A[q]恰好是第k小元素直接返回,假设第k小元素落在前半区间就到A[p,q-1]递归查找.否则到A[q+1,r]中递归查找. 3

从一个序列中获取前K大的数的一种方法

这个方法是利用快速排序的.在快速排序中,得到中间元素(pivot)之后,比较中间元素之前的元素个数和K的大小关系,从而确定后面该往哪个方向继续递归.如果中间元素前面的元素个数等于K,那就停止递归过程:如果中间元素前面元素个数小于K,那就再中间元素后面进行递归:否则就往中间元素前面进行递归.这样最终得到的是没有排序的前K大的元素,这样再对前K个元素进行一次真正的快速排序.这样就能得到排好序的前K大元素.我随机生成了一个100000个整型数据的文件进行测试,求前10000个元素.这样做用了0.984

mapreduce求前k个最大值(topk 问题)

需要先统计词频,再进行排序 ----------词频统计--------- package TopK; import java.io.IOException; import java.util.StringTokenizer; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; import org.apach

有序数组合并求第K大问题

题目描述 Description 给出两个有序数组A和B(从小到大有序),合并两个有序数组后新数组c也有序,询问c数组中第k大的数 假设不计入输入输出复杂度,你能否给出一个O(logN)的方法? 输入描述 Input Description 第一行输入三个整数n.m和k 第二行输入n个用空格隔开的整数表示数组A 第三行输入m个用空格隔开的整数表示数组B 输入保证A和B数组非递减 输出描述 Output Description 合并两个数组之后的第k大的数 样例输入 Sample Input 2

求两个有序序列合并成新有序序列的中位数,求第k小数

此算法涉及一个重要数学结论:如果A[k/2-1]<B[k/2-1],那么A[0]~A[k/2-1]一定在第k小的数的序列当中,可以用反证法证明. 更加一般的结论是:k=pa+pb,如果A[pa-1]<B[pb-1],那么A[0]~A[pa-1]一定在第k小的数的序列当中. 算法思想如下: 1,假设A长度为m,B长度为n,m>n,反之亦然. 2,拆分k=pa+pb. 3,如果A[pa-1]<b[pb-1],那证明第A[0]~A[pa-1]一定在合并后k小数序列中.所以,可以把A的前面

[csu/coj 1080]划分树求区间前k大数和

题意:从某个区间内最多选择k个数,使得和最大 思路:首先题目给定的数有负数,如果区间前k大出现负数,那么负数不选和更大,于是对于所有最优选择,负数不会出现,所以用0取代负数,问题便转化为区间的前k大数和. 划分树: [1  6  3  8  5  4  7  2] [6  8  5  7][1  3  4  2] [8  7][6  5][3  4][1  2] [8][7][6][5][4][3][2][1] 把快排的结果从上至下依次放入线段树,就构成了划分树,划分的意思就是选定一个数,把原序

HDU5102(树的前k路径+队列)

The K-th Distance Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 332    Accepted Submission(s): 90 Problem Description Given a tree, which has n node in total. Define the distance between two

前K个高频元素

数据结构--堆 Heap是一种数据结构具有以下的特点: 1)完全二叉树: 2)heap中存储的值是偏序: Min-heap: 父节点的值小于或等于子节点的值: Max-heap: 父节点的值大于或等于子节点的值: 1.堆的存储: 一般都用数组来表示堆,i结点的父结点下标就为(i–1)/2.它的左右子结点下标分别为2 * i + 1和2 * i + 2.如第0个结点左右子结点下标分别为1和2 2.堆的操作:insert 插入一个元素:新元素被加入到heap的末尾,然后更新树以恢复堆的次序. 每次插