📌  相关文章
📜  最小化 x 的值,使 |a1−x|^c+|a2−x|^c+···+|an−x|^c 的值最小化 c 的值为 1 和 2(1)

📅  最后修改于: 2023-12-03 15:10:36.142000             🧑  作者: Mango

最小化 x 的值,使 |a1−x|^c+|a2−x|^c+···+|an−x|^c 的值最小化 c 的值为 1 和 2

这个问题是一个经典的优化问题,通常被称为绝对值函数优化问题。而这里我们可以将 c 的值分别取 1 和 2,进行求解。

当 c=1 时

我们的目标是找一个 x 使得下式最小化:

$$|a_1-x| + |a_2-x| + \cdots + |a_n-x|$$

这个问题可以通过排序来简化。设 $a_1 \le a_2 \le \cdots \le a_n$,那么可以得到以下结论。

  • 如果 $n$ 为奇数,那么最优解是 $x=a_{\lfloor n/2 \rfloor+1}$
  • 如果 $n$ 为偶数,那么最优解是 $x=\frac{a_{n/2}+a_{n/2+1}}{2}$

简单证明一下,设 $x=a_k$,其中 $k<\lfloor n/2 \rfloor+1$。那么我们移动 $x$ 到 $a_{k+1}$ 上,值会下降吗?注意到 $|a_k-a_{k+1}|$ 是非负值,而 $|a_j-a_k|+|a_j-a_{k+1}|$ 中只有一项会发生变化,所以变化量必然非负,因此 $k$ 必须大于或等于 $\lfloor n/2 \rfloor+1$。而如果 $k$ 大于 $\lfloor n/2 \rfloor+1$,那么我们可以将 $x$ 移动到 $a_{k-1}$ 上,得到的值也更小。综上,我们只需要枚举 $k=\lfloor n/2 \rfloor+1$ 和 $k=n/2$ 即可。

代码实现:

#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 1e5+5;
int a[MAXN];
int main()
{
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> a[i];
    sort(a, a+n);
    int k = n/2;
    cout << min(abs(a[k]-a[0])+abs(a[k]-a[n-1]), abs(a[k-1]-a[0])+abs(a[k-1]-a[n-1])) << endl;
    return 0;
}
当 c=2 时

同样地,我们的目标是找一个 $x$ 使得下式最小化:

$$|a_1-x|^2 + |a_2-x|^2 + \cdots + |a_n-x|^2$$

我们可以对上式进行分开处理:

$$|a_i-x|^2 = (a_i-x)^2 = a_i^2-2a_ix+x^2$$

那么原式就变成了:

$$\sum\limits_{i=1}^n a_i^2 - 2\left(\sum\limits_{i=1}^n a_i\right)x + nx^2$$

这个形式的多项式开口向上,因此最小值就在 $x=\frac{\sum\limits_{i=1}^n a_i}{n}$ 处取到。当然,绝不需要显式计算这个数,因为只需要 $n$ 个元素的和即可。

代码实现:

#include <iostream>
using namespace std;
const int MAXN = 1e5+5;
int a[MAXN];
int main()
{
    int n;
    cin >> n;
    long long sum = 0;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
        sum += a[i];
    }
    long long ans = 0;
    for (int i = 0; i < n; i++)
        ans += (a[i]-sum)*(a[i]-sum);
    cout << ans << endl;
    return 0;
}

以上就是关于最小化 $x$ 的值,使 $|a_1−x|^c+|a_2−x|^c+\cdots+|a_n−x|^c$ 的值最小化的两道题目的解法说明。