题目出处
题目描述
有两个长度都是 N 的序列 A 和 B ,在 A 和 B 中各取一个数相加可以得到 N2 个和,求这 N2 个和中最小的 N 个。
输入格式
第一行一个正整数 N 。
第二行 N 个整数 Ai ,满足 Ai≤Ai+1 且Ai≤109 。
第三行 N 个整数 Bi ,满足 Bi≤Bi+1 且Bi≤109 。
数据规模
对于50%的数据中,满足 1≤N≤1000 。
对于100%的数据中,满足1≤N≤100000
。
输出格式
输出仅一行,包含 N 个整数,从小到大输出这 N 个最小的和,相邻数字之间用空格隔开。
输入输出样例
输入样例
3
2 6 6
1 4 8
输出样例
3 6 7
AC代码与思路
两个数组输入的数是有序
的。
数学方法
若数组 A 和数组 B 有序,且 A[ i ]+B[ j ] 是 A[ k ]+B[ m ] 中前N小的值,那么必然有:A[ i ]*B[ j ] ≤ N
。其中 1≤ i ≤N,1≤ j ≤N,1≤ k ≤N,1≤ m ≤N。
#include <stdio.h>
#include <algorithm>
using namespace std;
int main()
{
int i, j, k = 0;
int n;
int NumSet1[100000] = {0};
int NumSet2[100000] = {0};
static int Sum[1300000] = {0};
scanf("%d", &n);
for (i = 0; i < n; i++)
scanf("%d", &NumSet1[i]);
for (i = 0; i < n; i++)
scanf("%d", &NumSet2[i]);
for (i = 0; i < n; i++)
for (j = 0; (i + 1) * (j + 1) <= n; j++)
Sum[k++] = NumSet1[i] + NumSet2[j];
partial_sort(Sum, Sum + k, Sum + k);
for (i = 0; i < n; i++)
printf("%d ", Sum[i]);
printf("\n");
}
优先队列
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
#define MaxSize 100010
typedef struct SumWithFactor
{
int FactorANo;
int FactorBNo;
int Sum;
//优先队列默认大顶堆,改变"<"定义,使其变成小顶堆
bool friend operator<(SumWithFactor Sum1, SumWithFactor Sum2)
{
return Sum1.Sum > Sum2.Sum;
}
} SumWithFactor;
int main()
{
int n;
int NoA, NoB;
int NumSetA[MaxSize] = {0}, NumSetB[MaxSize] = {0};
SumWithFactor Temp;
priority_queue<SumWithFactor> SumList;
//关闭流同步
ios::sync_with_stdio(false);
cin >> n;
for (int i = 0; i < n; ++i)
cin >> NumSetA[i];
for (int i = 0; i < n; ++i)
cin >> NumSetB[i];
//生成一个长度为n的优先队列
//该队列由A[i]+B[0]组成(i=0,1,2……,n-1)
for (int i = 0; i < n; ++i)
{
Temp.FactorANo = i;
Temp.FactorBNo = 0;
Temp.Sum = NumSetA[i] + NumSetB[0];
SumList.push(Temp);
}
//若A[i]+B[j]被取出队列,将A[i]+B[j+1]放入队列
//按此取出n个元素,该n个元素即为最小的n个元素
for (int i = 0; i < n; ++i)
{
Temp = SumList.top();
cout << Temp.Sum << " "; //注意输出格式
SumList.pop();
++Temp.FactorBNo;
Temp.Sum = NumSetA[Temp.FactorANo] + NumSetB[Temp.FactorBNo];
SumList.push(Temp);
}
return 0;
}