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 }
代码君

 

你可能感兴趣的:(优先队列)