当前位置: 代码迷 >> 综合 >> K个最小和(K Smallest Sums,UVA-11997 )多路归并
  详细解决方案

K个最小和(K Smallest Sums,UVA-11997 )多路归并

热度:75   发布时间:2023-11-22 01:08:00.0

题目链接

https://vjudge.net/problem/UVA-11997

题意

给定k个数组,每个数组有k个值。从每个数组中选一个值,然后对所选值累加求和。问这k^k个和中最小的k个分别是多少。将其升序输出。

分析

参考自刘汝佳《白书》中解法:多路归并。

先考虑简化情况:k=2.k=2时,和有k^2个,将这k^2个元素排序后,前k个即为所求。
多路归并是归并排序的升级版。
算法过程:
将k^2个和分成k个有序数组,每个数组有k个元素。用优先队列来维护每个数组中的最小值,通过k次出队、入队就可以得到最终结果。

对于k>2的情况,两两合并即可。

代码

#include <bits/stdc++.h>
using namespace std;const int maxn=760;struct node
{int sum,p;//node(int sum,int p):sum(sum),p(p){}bool operator<(const node &o)const{return sum>o.sum;}};
void merge(int *a,int *b,int *c,int n)
{priority_queue<node> que;for(int i=0;i<n;i++)que.push(node{a[i]+b[0],0});for(int i=0;i<n;i++){node t=que.top();que.pop();c[i]=t.sum;if(t.p+1<n) que.push(node{t.sum-b[t.p]+b[t.p+1],t.p+1});}
}
int ac[maxn][maxn];
int main()
{int k;while(cin>>k){for(int i=0;i<k;i++)for(int j=0;j<k;j++)cin>>ac[i][j];for(int i=0;i<k;i++)sort(ac[i],ac[i]+k);for(int i=1;i<k;i++)merge(ac[0],ac[i],ac[0],k);for(int i=0;i<k;i++){if(i) cout<<" "<<ac[0][i];else cout<<ac[0][i];}cout<<endl;}return 0;
}