zoukankan      html  css  js  c++  java
  • 【UVA 11997 K Smallest Sums】优先级队列

    来自《训练指南》优先级队列的例题。

    题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18702

    题意:给定k个整数数组,各包含k个元素。在每个数组中取一个元素加起来,可以得到kk个和,求这些和中最小的k个值(不去重)。

    数据范围:k [2, 750]

    思路:暴力枚举k^k不可取。

    “先来看问题的简化版:给出两个长度为k的数组A和B,分别在A和B中任取一个数并相加,可以得到k^2个和,求这些和中最小的k个。”

    首先把A, B从小到大排序。由于只求最小的前k个值,我们可以先假定B[0]与A的k个元素分别相加得到的元素集合S就是最小的k个和,然后每次取出S的最小值Smin保存到结果数组R中,并把Smin减去B[i]、加上B[i+1]后得到的值再放回集合S中,保持S的大小总为k。这样经过k轮取出-放回操作后,R中的k个元素就是结果。我们把这一操作过程叫作A,B的合并。合并一次的复杂度为O(klogk)

    S需要k次插入和删除,每次只取最小值,因此数据结构选用完全二叉堆实现的优先级队列很合适。

    现在由两个数组A,B扩展到k个数组A1~Ak,只需把A1看作A, 依次处理 i: 2~k,每次把Ai合并到A1中,这样经过k次两两合并后,A1中的k个数就是结果。总的复杂度O(k2logk)

     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <queue>
     4 using namespace std;
     5 const int MAX_K = 760;
     6 
     7 struct Elem{
     8     int sum, b;
     9     Elem(int s, int b):sum(s), b(b){}
    10     Elem& operator = (const Elem& e){
    11         sum = e.sum;
    12         b = e.b;
    13         return *this;
    14     }
    15     bool operator < (const Elem& e) const{
    16         return sum > e.sum; //小顶堆 
    17     }
    18 };
    19 
    20 void merge(int* A, int* B, int n){
    21     priority_queue<Elem> pq;
    22     for(int i=0; i<n; i++){
    23         pq.push(Elem(A[i] + B[0], 0));
    24     }
    25     for(int i=0; i<n; i++){
    26         Elem e = pq.top();
    27         A[i] = e.sum;
    28         pq.pop();
    29         e.sum = e.sum - B[e.b] + B[e.b+1];
    30         e.b = e.b + 1;
    31         pq.push(e);
    32     }
    33 //    for(int i=0; i<n; i++){
    34 //        printf("%d ", A[i]);
    35 //    }
    36 //    printf("
    ");
    37 }
    38 
    39 int k;
    40 int a[MAX_K], b[MAX_K];
    41 
    42 int main()
    43 {
    44     freopen("11997.txt", "r", stdin);
    45     while(~scanf("%d", &k)){
    46         for(int i=0; i<k; i++){
    47             scanf("%d", &a[i]);
    48         }
    49         sort(a, a+k);
    50         for(int i=1; i<k; i++){
    51             for(int j=0; j<k; j++){
    52                 scanf("%d", &b[j]);
    53             }
    54             sort(b, b+k);
    55             merge(a, b, k);
    56         }
    57         printf("%d", a[0]);
    58         for(int i=1; i<k; i++){
    59             printf(" %d", a[i]);
    60         }
    61         printf("
    ");
    62     }
    63     return 0;
    64 }
  • 相关阅读:
    年底送书活动:送出6本技术书籍,价值372元!
    (7)ASP.NET WEB服务器控件
    (6)DataTable 转换成 Json
    (9)C#连mysql
    (8)C#连sqlserver
    VM虚拟机
    (7)C#连DB2---oledb方式
    (48)C#网络4 web
    远程桌面
    (47)C#运行时序列化
  • 原文地址:https://www.cnblogs.com/helenawang/p/5497856.html
Copyright © 2011-2022 走看看