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

考虑一个简单的问题,两个长度为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数组其实是先读后写的。

 1 #include <cstdio>
 2 #include <queue>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 const int maxn = 750 + 10;
 7 int a[2][maxn];
 8 
 9 void scan(int& x)
10 {
11     char c;
12     while(c = getchar(), c < '0' || c > '9');
13     x = c - '0';
14     while(c = getchar(), c >= '0' && c <= '9') x = x*10 + c - '0';
15 }
16 
17 struct Node
18 {
19     int sum, b;
20     Node(int s, int b):sum(s), b(b) {}
21     bool operator < (const Node& rhs) const
22     { return sum > rhs.sum; }
23 };
24 
25 void merge(int n, int* A, int* B, int* C)
26 {
27     priority_queue<Node> Q;
28     for(int i = 0; i < n; i++) Q.push(Node(A[i]+B[0], 0));
29 
30     for(int i = 0; i < n; i++)
31     {
32         Node t = Q.top(); Q.pop();
33         int b = t.b, sum = t.sum;
34         C[i] = sum;
35         if(b + 1 < n) Q.push(Node(sum-B[b]+B[b+1], b+1));
36     }
37 }
38 
39 int main()
40 {
41     //freopen("in.txt", "r", stdin);
42 
43     int k;
44     while(scanf("%d", &k) == 1)
45     {
46         for(int i = 0; i < k; i++) scan(a[0][i]);
47         sort(a[0], a[0] + k);
48         for(int i = 1; i < k; i++)
49         {
50             for(int j = 0; j < k; j++) scan(a[1][j]);
51             sort(a[1], a[1] + k);
52             merge(k, a[0], a[1], a[0]);
53         }
54 
55         for(int i = 0; i < k; i++)
56         {
57             if(i) printf(" ");
58             printf("%d", a[0][i]);
59         }
60         puts("");
61     }
62 
63     return 0;
64 }
代码君
原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4341882.html