思路题,多路归并(K Smallest Sums,UVA 11997)
来源:互联网 发布:在家网络兼职招聘 编辑:程序博客网 时间:2024/06/06 03:34
最简单的多路归并就是归并排序,只需要将两个有序表合成为1个有序表即可。首先表只有2个,其次限制条件也只有挑一个最小的。所以非常简单。实现方法往往是弄两个指针,然后看哪个指针指向的值小,就把哪个值放进来,然后指针++。
但是有时我们会遇到更为复杂的问题,比如说有多个有序表,而且限制条件又比较复杂的情况,有时甚至连我们该归并什么,有序表里该放什么都不知道。
这时我们就最好要有一些多路归并的经验了。
大白书P189上写的一些话很值得仔细看懂,它揭露了前面那道水题——例题3的本质。
“推而广之,我们实际上已经学会解决多路归并问题,即把k个有序表合并成一个有序表(假定每个表都是升序排序)——用优先队列维护每个表的“当前元素”。
注意下,一个数组不等于一个有序表。
一个有序表就是一路。
而例题4就需要更加灵活的思路了——题目说k个数组中,每个数组挑且只挑一个数,然后全部加起来,最后求k个最优值。那我们不妨一个数组一个数组地加进来,然后一加一边维护k个最优值就好了。这样就只需要考虑如何解决两个数组相加的问题了。
题目限制为每个数组里都要挑一个,然后求和。只考虑两个数组的话,那就是这两个数组里各挑一个,然后相加。
那么有序表是什么呢?一个表内的元素一定是一个跟着一个的,前面的走了,后面的才能来,即每次只能出一个代表。表内的元素是可以互相替代的,只不过要挑一个最优的出来,表间的元素是不可相互替代的,而且他们并起来一定是全集。
那就先找不可相互替代的咯。
很快就发现,一个数组内的数都是不可相互替代的(能且只能取一个),因此他们各自成一个表。每个数都可以任意搭配另一个数组内的任意一个数,那么对于某个数,它的所有搭配都是可以相互替代的(因为对于某个数,它的所有搭配都可以代表这个数),所以在一个表内。最终保证了优先队列里始终没有重复和遗漏的元素。
然后就“用优先队列维护每个表的“当前元素””就好了。
反正就是两个数组的话,先按一个数组分类,然后用另一个数组搭配。
分类分得不重不漏,每类都包含所有可能的搭配,每类出一个最优的搭配,再在其中挑一个最优的。保证是最优解,然后把这个最优解删去,即“当前元素”变成了“次选”,然后不断重复。优点是只用动态地保存前k个最优解,不需要枚举所有情况。挑选以及删除的过程有点像堆。嗯,优先队列是个二叉的堆,而这个是多叉的堆。
代码
#include<bits/stdc++.h>#define f(i) for(int i=0;i<n;i++)#define s(a) scanf("%d",&a)#define ss(A,i) scanf("%d",A+i)using namespace std;typedef pair<int,int> pii;int n;int A[800];int B[800];void mg(int*A,int*B,int*C){ priority_queue<pii,vector<pii>,greater<pii> >q; f(i) q.push(make_pair(A[i]+B[0],0)); f(i) { C[i]=q.top().first; q.push(make_pair(q.top().first-B[q.top().second]+B[q.top().second+1],q.top().second+1)); q.pop(); }}int main(){ while(~s(n)) { f(i) ss(A,i); sort(A,A+n); int num=n-1; while(num--) { f(i) ss(B,i); sort(B,B+n); mg(A,B,A); } f(i) printf("%d%c",A[i],i==n-1?'\n':' '); } return 0;}
- 思路题,多路归并(K Smallest Sums,UVA 11997)
- UVA 11997 K Smallest Sums (多路归并)
- UVA 11997 - K Smallest Sums(多路归并)
- Uva 11997 - K Smallest Sums(多路归并)
- Uva 11997 - K Smallest Sums(多路归并)
- K Smallest Sums(Uva 11997) 多路归并+优先队列
- UVa - 11997 K Smallest Sums(优先队列多路归并)
- (UVa 11997)K Smallest Sums --多路归并问题,优先队列
- UVA K Smallest Sums(多路归并,优先队列)
- UVA 11997 K Smallest Sums(多路归并求前k个最小和的值)
- UVA 11997--K Smallest Sums+优先队列用于多路归并
- UVa 11997 K Smallest Sums (优先队列 & k路归并化为两两归并)
- UVA - 11997 K Smallest Sums 归并排序+优先队列
- UVA 11997 - K Smallest Sums(优先队列+多路合并)
- UVA 11997 K Smallest Sums(多路合并)
- UVa - 11997 - K Smallest Sums
- UVa - 11997 - K Smallest Sums
- Uva-11997-K Smallest Sums
- NodeJS搭建博客系统(二)构建一个markdown页面
- BZOJ 1036 [ZJOI2008] 树的统计Count
- python3使用pickle读取文件提示TypeError或者UnicodeDecodeError的解决办法
- java常用加密方式2
- 《初入linux》--第二十部分-Apache服务器的几个实用技巧
- 思路题,多路归并(K Smallest Sums,UVA 11997)
- html的超链接
- 操作系统与网络实现 之十九(甲)
- Linux 文件编码大挪移
- iOS OC与JS的交互(JavaScriptCore实现)
- 2016/12/8学习工作总结
- c
- linux下面识别USB的四种方式
- 大数据的处理