最小向量点积
最小向量点积
1049. 最小向量点积
题目描述
定义
向量 $\mathbf{a} = [a_1, a_2, \dots, a_n]$ 与 $\mathbf{b} = [b_1, b_2, \dots, b_n]$ 的点积定义为:
\[\mathbf{a} \cdot \mathbf{b} = \sum_{i=1}^{n} a_i b_i = a_1 b_1 + a_2 b_2 + \cdots + a_n b_n\]示例:向量 $[1, 3, -5]$ 与 $[4, -2, -1]$ 的点积:
\[(1)(4) + (3)(-2) + (-5)(-1) = 4 - 6 + 5 = 3\]问题
允许对每个向量内部的坐标值重新排列,求所有可能排列组合中点积的最小值。
示例最优解:将 $[1, 3, -5]$ 排列为 $[3, 1, -5]$,将 $[4, -2, -1]$ 排列为 $[-2, -1, 4]$,点积为:
\[3 \times (-2) + 1 \times (-1) + (-5) \times 4 = -6 - 1 - 20 = -27\]输入格式
- 第 1 行:整数 $T$($1 \le T \le 10$),表示问题数
- 每个问题:
- 第 1 行:整数 $n$($1 \le n \le 1000$),维数
- 第 2 行:向量 $\mathbf{a}$ 的 $n$ 个整数($-1000 \le a_i \le 1000$)
- 第 3 行:向量 $\mathbf{b}$ 的 $n$ 个整数($-1000 \le b_i \le 1000$)
输出格式
每个问题输出一行:case #k: min_dot_product,其中 $k$ 从 0 开始。
题解
思路
根据重排不等式(Rearrangement Inequality):
两个数列,一个升序排列、另一个降序排列时,对应项乘积之和最小。
证明直觉:让大的数和小的数配对,可以”抵消”掉更多的值,使总和最小。
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
for (int k = 0; k < T; k++) {
int n;
cin >> n;
vector<long long> a(n), b(n);
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 0; i < n; i++) cin >> b[i];
// a 升序,b 降序
sort(a.begin(), a.end());
sort(b.begin(), b.end(), greater<long long>());
long long ans = 0;
for (int i = 0; i < n; i++) {
ans += a[i] * b[i];
}
cout << "case #" << k << ": " << ans << "\n";
}
return 0;
}
复杂度分析
- 时间复杂度:$O(n \log n)$(排序)
- 空间复杂度:$O(n)$
本文由作者按照 CC BY 4.0 进行授权