您的位置:首页 > 其它

UVa 11997 (优先队列 多路归并) K Smallest Sums

2015-03-16 15:10 337 查看
考虑一个简单的问题,两个长度为n的有序数组A和B,从每个数组中各选出一个数相加,共n2中情况,求最小的n个数。

将这n2个数拆成n个有序表:

A1+B1≤A1+B2≤...

A2+B1≤A2+B2≤...

...

An+B1≤An+B2≤...

然后用优先队列合并成一个有序表即可。队列中需要记录两个数的和s,以及在B中的下标b,

比如Aa+Bb出队以后,应该将Aa+B(b+1) = Aa + Bb - Bb + Bb+1 = s - Bb + bb+1入队

对于书上最后的一个思考问题,merge函数中对A[0]又读又写,会不会出错。答案当然是不会的,因为进入到函数内部你会发现,对A数组其实是先读后写的。

#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;

const int maxn = 750 + 10;
int a[2][maxn];

void scan(int& x)
{
char c;
while(c = getchar(), c < '0' || c > '9');
x = c - '0';
while(c = getchar(), c >= '0' && c <= '9') x = x*10 + c - '0';
}

struct Node
{
int sum, b;
Node(int s, int b):sum(s), b(b) {}
bool operator < (const Node& rhs) const
{ return sum > rhs.sum; }
};

void merge(int n, int* A, int* B, int* C)
{
priority_queue<Node> Q;
for(int i = 0; i < n; i++) Q.push(Node(A[i]+B[0], 0));

for(int i = 0; i < n; i++)
{
Node t = Q.top(); Q.pop();
int b = t.b, sum = t.sum;
C[i] = sum;
if(b + 1 < n) Q.push(Node(sum-B[b]+B[b+1], b+1));
}
}

int main()
{
//freopen("in.txt", "r", stdin);

int k;
while(scanf("%d", &k) == 1)
{
for(int i = 0; i < k; i++) scan(a[0][i]);
sort(a[0], a[0] + k);
for(int i = 1; i < k; i++)
{
for(int j = 0; j < k; j++) scan(a[1][j]);
sort(a[1], a[1] + k);
merge(k, a[0], a[1], a[0]);
}

for(int i = 0; i < k; i++)
{
if(i) printf(" ");
printf("%d", a[0][i]);
}
puts("");
}

return 0;
}


代码君
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: