Source : UVA - 11997 K Smallest Sums
有k个整数数组,各包含k个元素,从每个数组中选取一个元素加起来,可以得到k^k个和,求这些和中最小的k个值。
Sample Input
3
1 8 5
9 2 5
10 7 6
2
1 1
1 2
Sample Output
9 10 12
2 2
二路归并构建二维平面表:
首先将第一列入队,第一列的最小值即为全局的最小值;接下来定位到最小值的那一行,跳过这一个元素,把下一个元素入队,始终保持priority_queue中有n个元素,队首元素即为全局下一小的元素和,记录即可。
多路归并就要构建三位立体表:想象下
逐层二路合并即可。
#include<bits/stdc++.h>
using namespace std;
const int _max = 750 + 10;
int n,A[_max],B[_max];
struct Item{
int s,b;//(s,b) s = Aa + Bb
Item (){}
Item(int s,int b):s(s) , b(b){}//构造函数
bool operator < (const Item& a) const{//定义优先级
return s > a.s;
}
};
priority_queue<Item>pq;
Item item;
void merge(int A[],int B[],int C[]){//二路归并,前n个最小和存于C[]
while(!pq.empty()) pq.pop();
for(int i = 0; i < n; ++ i){
item = Item(A[i] + B[0],0);
pq.push(item); //第一列元素入队
}
for(int i = 0; i < n; ++ i){//O(nlogn)
item = pq.top();pq.pop();
C[i] = item.s;//第一列最小的一定是全局最小,跳过它读取同一行的下一个元素入队,循环n次
int b = item.b;
if(b + 1 < n) pq.push(Item(item.s - B[b] + B[b+1],b + 1));
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("input.txt","r",stdin);
#endif // ONLINE_JUDGE
while(scanf("%d",&n) == 1){
for(int i = 0; i < n; ++ i) //先读一路数据
scanf("%d",A + i);
sort(A , A + n);
for(int i = 1; i < n; ++ i){ //以二路为基础做多路归并
for(int j = 0; j < n; ++ j) scanf("%d",B+j);
sort(B,B+n);
merge(A,B,A);//A[]元素只用做初始化,所以在合并过程可以直接把结果存储到A中
}
printf("%d",A[0]);//输出格式
for(int i = 1; i < n; ++ i) printf(" %d",A[i]);
printf("\n");
}
return 0;
}
Ctrl + B
Ctrl + I
Ctrl + Q
Ctrl + L
Ctrl + K
Ctrl + G
Ctrl + H
Ctrl + O
Ctrl + U
Ctrl + R
Ctrl + Z
Ctrl + Y
版权声明:本文为博主原创文章,未经博主允许不得转载。
【优先队列之多路合并】UVA - 11997 K Smallest Sums
原文:http://blog.csdn.net/u012717411/article/details/48053293