码迷,mamicode.com
首页 > 其他好文 > 详细

UVA11997 K Smallest Sums

时间:2020-01-06 09:53:58      阅读:55      评论:0      收藏:0      [点我收藏+]

标签:lin   first   printf   break   优先   vector   cst   while   void   

题目

一句话题意 , 有 k 个长为 k 的序列 , 从其中每个序列选一个数 \(k^k\) 个和中输出前k小

考虑 有两个长为n的序列 , 从他们中选出\(n\)最小的和 , 可以用一个很妙的想法

在优先队列里 , 存\((a_1 + b_1 , 1) , (a_2 + b_1 , 1) , (a_3 + b_1 , 1) \dots\)

第一个是 a+b , 第二项是b的下标 , 每次取出最小的 , 然后把 \(x - b[id] + b[id] + 1\) 放进去(b 是排好序的)

取 n 遍就行, 而有 k 个的序列的情况两两合并就可以了,正确性贪心可证 ,不写了。。。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 756;
int n;
int a[N] , b[N];
priority_queue< pair<int,int> , vector< pair<int,int> > , greater< pair<int,int> > > q; 
void Merge()
{
    while(q.size()) q.pop();
    for(int i = 1 ; i <= n ; ++i) q.push(make_pair(a[i] + b[1] , 1));
    int tot = 0;
    while(q.size())
    {
        int x = q.top().first , y = q.top().second; q.pop();
        a[++tot] = x; if(tot == n) break; 
        if(y < n) q.push(make_pair(x - b[y] + b[y+1] , y+1));
    }
    return ;
}

int main()
{
    while(scanf("%d" , &n) == 1)
    {
        for(int i = 1 ; i <= n ; ++i) scanf("%d",&a[i]); // 这里要先读进去一遍a , 不然直接合并就是 n 个 0 与 b 合并 
        for(int j = 2 ; j <= n ; ++j)
        {
            for(int i = 1 ; i <= n ; ++i) scanf("%d",&b[i]);
            sort(b + 1 , b + 1 + n);
            Merge();
        }
        printf("%d",a[1]);
        for(int i = 2 ; i <= n ; ++i) printf(" %d" , a[i]); puts("");
    }
    return 0;
}

UVA11997 K Smallest Sums

标签:lin   first   printf   break   优先   vector   cst   while   void   

原文地址:https://www.cnblogs.com/R-Q-R-Q/p/12154607.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!