UVa11997K Smallest Sums(优先队列)
K Smallest Sums
You're given k arrays, each array has k integers. There are kk ways to pick exactly one element in each array and calculate the sum of the integers. Your task is to find the k smallest sums among them.
Input
There will be several test cases. The first line of each case contains an integer k (2<=k<=750). Each of the following k lines contains k positive integers in each array. Each of these integers does not exceed 1,000,000. The input is terminated by end-of-file (EOF). The size of input file does not exceed 5MB.
Output
For each test case, print the k smallest sums, in ascending order.
Sample Input
3
1 8 5
9 2 5
10 7 6
2
1 1
1 2
Output for the Sample Input
9 10 12
2 2 题目大意:
给定一个k*k的一个矩阵,如果让你在每一行取出一个数,再将每一行取出的数相加,那么总共可以得到k^k种相加方法,现在让你求出这k^k个结果中最小的k个结果。 分析:
咋一看,的确很难有想法,但是仔细分析这个题目我们会发现其实这个问题是满足最优子结构的,比如:
如果我们已经计算出了前m行,每行取出一个数相加的最小的k个结果,分别是DP[1],DP[2]...DP[k](注意这里的DP表示的是前m行每行一个相加的最小的前k个值)
假设第m+1行的值是A[1],A[2]...A[k] (注意这里的A[i]表示的是第m+1行的第i个数)
当我们推倒到第m+1行时,由于我们只计算了前m行的前k个最小值,那我们是不是有必要多计算一些来推导出第m+1行的前k个最小值呢, 答案是不必要的,我们可以通过以下数学公式严格证明:
设DP[x]是前m行通过计算得出的第x(x>k)小的和,如果上述的假设成立,那么我们可以列出不等式:
DP[x] + A[y] < DP[m] + A[n] (1) (DP[m]+A[n]表示只通过DP[1,2...k]计算出的前m+1行第k小的和)
上述不等式的含义是指在第m+1行存在一个数A[y],使得DP[x]+A[y]是前m+1行中前k小的结果。
同时,我们注意到: x>k ==> DP[x] > DP[k] (2)
而且: A[y] >= A[1] (3)
由上面三个不等式(1),(2),(3)我们可以得到:
DP[k]+A[1] <= DP[x]+A[y] < DP[m]+A[n]
也就是 DP[k]+A[1] < DP[m]+A[n]
之前我们说过DP[m] + A[n] 是前m行第k大的和,然而:比DP[k]+A[1]小的数已经有
(DP[1]+A[1]),(DP[2]+A[1])...(DP[k-1]+A[1])共计k-1个,
所以DP[k]+A[1]是第k个最小的和,与假设的DP[m]+A[n]是第k个最小的和相矛盾,所以假设不成立。
得证。 通过以上的证明我们可以得出结论要计算第m+1行的前k个最小和是只需要计算出前m行的前k个最小的和即可。
这时,我们的目标就转化为了计算一个2*k的数组,在第一行取一个数,在第二行取一个数,得到k^2个和,求他们当中的最小的k个和。 为了计算它,我们把这n^2个数组织成如下n个有序表:
表1: A1+B1 <= A1+B2<=A1+B3<=......
表2: A2+B1 <= A2+B2<=A2+B3<=......
.
表n: An+B1 <= An+B2<=An+B3<=...... 这时我们用一个二元组(sum, b)来保存以上的每一个元素,其中sum=A[a] + B[b].为什么不保存A的下标a呢?因为我们用不到a的值。如果我们需要在表(sum, b)中赵到下一个元素(sum', b+1),只要计算sum' = s - B[b] + B[b+1],不需要知道a是多少。
struct Item {
int sum, b; //s = A[a] + B[b]
Item(int _s, int _b)
{
sum = _s;
b = _b;
}
bool operator < (const Item& rhs) const {
return sum > rhs.sum;
}
};
至于如何合并,见代码:(其中merge的功能是将a和b数组合并到一个数组a中,最后的结果保存在a中)
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define inf -0x3f3f3f3f
#define lson k<<1, L, mid
#define rson k<<1|1, mid+1, R
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a, b) memset(a, b, sizeof(a))
#define FOPENIN(IN) freopen(IN, "r", stdin)
#define FOPENOUT(OUT) freopen(OUT, "w", stdout) template<class T> T CMP_MIN(T a, T b) { return a < b; }
template<class T> T CMP_MAX(T a, T b) { return a > b; }
template<class T> T MAX(T a, T b) { return a > b ? a : b; }
template<class T> T MIN(T a, T b) { return a < b ? a : b; }
template<class T> T GCD(T a, T b) { return b ? GCD(b, a%b) : a; }
template<class T> T LCM(T a, T b) { return a / GCD(a,b) * b; } //typedef __int64 LL;
typedef long long LL;
const int MAXN = ;
const int MAXM = ;
const double eps = 1e-; struct NODE
{
int s, b;
NODE(){}
NODE(int _s,int _b)
{
s = _s;
b = _b;
}
bool operator < (const NODE& B)const{
return s > B.s;
}
};
int k, a[MAXN], b[MAXN]; void mergeArray()
{
priority_queue<NODE>q;
for(int i = ; i < k; i++)
{
q.push(NODE(a[i]+b[], ));
}
for(int i=;i<k;i++)
{
NODE top = q.top(); q.pop();
a[i] = top.s;
int id = top.b;
if(id+ < k) q.push(NODE(top.s+b[id+]-b[id], id+));
}
} int main()
{
// FOPENIN("in.txt");
// FOPENOUT("out.txt");
while(~scanf("%d", &k))
{
mem0(a);
for(int i=;i<k;i++) scanf("%d", &a[i]);
for(int i=;i<k;i++)
{
for(int j=;j<k;j++) scanf("%d", &b[j]);
sort(b,b+k);
mergeArray();
}
for(int i=;i<k;i++)
{
printf("%d%c", a[i],i==k-?'\n':' ');
}
}
return ;
}
UVa11997K Smallest Sums(优先队列)的更多相关文章
- 11997 - K Smallest Sums(优先队列)
11997 - K Smallest Sums You’re given k arrays, each array has k integers. There are kk ways to pick ...
- UVa 11997 K Smallest Sums 优先队列&&打有序表&&归并
UVA - 11997 id=18702" target="_blank" style="color:blue; text-decoration:none&qu ...
- uva 11997 K Smallest Sums 优先队列处理多路归并问题
题意:K个数组每组K个值,每次从一组中选一个,共K^k种,问前K个小的. 思路:优先队列处理多路归并,每个状态含有K个元素.详见刘汝佳算法指南. #include<iostream> #i ...
- UVa 11997 K Smallest Sums - 优先队列
题目大意 有k个长度为k的数组,从每个数组中选出1个数,再把这k个数进行求和,问在所有的这些和中,最小的前k个和. 考虑将前i个数组合并,保留前k个和.然后考虑将第(i + 1)个数组和它合并,保留前 ...
- UVA 11997 K Smallest Sums 优先队列 多路合并
vjudge 上题目链接:UVA 11997 题意很简单,就是从 k 个数组(每个数组均包含 k 个正整数)中各取出一个整数相加(所以可以得到 kk 个结果),输出前 k 小的和. 这时训练指南上的一 ...
- uva_11997,K Smallest Sums优先队列
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #inclu ...
- 373. Find K Pairs with Smallest Sums (java,优先队列)
题目: You are given two integer arrays nums1 and nums2 sorted in ascending order and an integer k. Def ...
- 【暑假】[实用数据结构]UVa11997 K Smallest Sums
UVa11997 K Smallest Sums 题目: K Smallest Sums You're given k arrays, each array has k integers. Ther ...
- [LeetCode] Find K Pairs with Smallest Sums 找和最小的K对数字
You are given two integer arrays nums1 and nums2 sorted in ascending order and an integer k. Define ...
随机推荐
- 安装 Visual Stuidio 2010 失败
百思不得其解,尝试解压安装iso文件,解压都正常,怀疑Daemon Tools 是不是有问题? 最终问题还是定位在文件出问题了.SHA值不一样,囧!
- BZOJ3028: 食物
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3028 题解:列出母函数乘起来化简之后再展开,用插板法即可. 代码: #include<c ...
- [转]使用 jQuery Mobile 与 HTML5 开发 Web App —— jQuery Mobile 事件详解
在前文<使用 jQuery Mobile 与 HTML5 开发 Web App —— jQuery Mobile 默认配置与事件基础>中,Kayo 对 jQuery Mobile 事件的基 ...
- poj 1236 Network of Schools(强连通、缩点、出入度)
题意:给出一个有向图.1:问至少选出多少个点,才能沿有向边遍历所有节点.2:问至少加多少条有向边,使原图强连通. 分析:第一个问题,缩点后找所有树根(入度为0).第二个问题,分别找出入度为0和出度为0 ...
- android架构图示
Android系统架构和一些普遍的操作系统差不多,都是采用了分层的架构,从他们之间的架构图看,Android系统架构分为四个层,从高层到低层分别是应用程序层.应用程序框架层.系统运行库层和linux核 ...
- Comparator与Comparable的异同
同 它们都是Java的一个接口,都是用来实现集合中元素的比较.排序. 异 Comparator位于java.util下: Comparable位于java.lang下: Comparable(可比较的 ...
- 一天一个Java基础——通过异常处理错误
<Thinking in Java>上对这章的讲解不少,可见重要性,学习和总结一些主要的记录下来. 一.创建自定义异常 package Exception; class SimpleExc ...
- 【转】Eclipse+PyDev 安装和配置
原文网址:http://www.51testing.com/html/67/589567-866611.html Python开发有很多工具,其中Eclipse+Pydev 是最常见的一种.本文简单介 ...
- Linux系统性能诊断工具纲要
Linux的性能分析工具众多,在微博上发现了系统性能专家Brendan D. Gregg,在最近LinuxCon NA 2014大会上发布的关于Linux性能方面的talk和幻灯片.和去年比较,今年增 ...
- 【PHP入门到精通】:Ch05:字符串处理
Ch05: 字符串简介 5.1 字串说明 字符串是指由>=0个字符构成的一串字符,所以叫字符串.这里所说的字符主要包括以下几种类型:数字类型:如1, 2, 3, 4等.字母类型:如果a, b, ...