贪心-acwing-104-货仓选址

贪心-acwing-104-货仓选址

题目:
在一条数轴上有 N 家商店,它们的坐标分别为 A1~AN。

现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品。

为了提高效率,求把货仓建在何处,可以使得货仓到每家商店的距离之和最小。

输入格式
第一行输入整数N。

第二行N个整数A1~AN。

输出格式
输出一个整数,表示距离之和的最小值。

数据范围
1≤N≤100000
输入样例:
4
6 2 9 1
输出样例:
12

题解:

设 仓 库 选 址 为 x , 即 求 m i n ( ∑ i = 1 n ∣ A i − x ∣ ) 。 设仓库选址为x,即求min(\sum_{i=1}^{n}|A_i-x|)。 x,min(i=1nAix)

我 们 知 道 对 于 任 意 三 点 a , b , c , ∣ a − c ∣ + ∣ b − c ∣ 最 小 值 为 ∣ a − b ∣ , 当 且 仅 当 点 c 在 点 a , b 之 间 时 取 到 。 我们知道对于任意三点a,b,c,|a-c|+|b-c|最小值为|a-b|,当且仅当点c在点a,b之间时取到。 a,b,cac+bcabca,b

那 么 我 们 将 ∑ i = 1 n ∣ A i − x ∣ = ∣ A 1 − x ∣ + ∣ A 2 − x ∣ + . . . + ∣ A n − 1 − x ∣ + ∣ A n − x ∣ 进 行 分 组 配 对 那么我们将\sum_{i=1}^{n}|A_i-x|=|A_1-x|+|A_2-x|+...+|A_{n-1}-x|+|A_n-x|进行分组配对 i=1nAix=A1x+A2x+...+An1x+Anx

∑ i = 1 n ∣ A i − x ∣ = ( ∣ A 1 − x ∣ + ∣ A n − x ∣ ) + ( ∣ A 2 − x ∣ + ∣ A n − 1 − x ∣ ) + . . . \sum_{i=1}^{n}|A_i-x|=(|A_1-x|+|A_n-x|)+(|A_2-x|+|A_{n-1}-x|)+... i=1nAix=(A1x+Anx)+(A2x+An1x)+...

上 式 子 取 到 最 小 值 当 且 仅 当 x 在 A 1 和 A n 之 间 , 在 A 2 和 A n − 1 之 间 . . . 上式子取到最小值当且仅当x在A_1和A_n之间,在A_2和A_{n-1}之间... xA1AnA2An1...

因 此 我 们 先 将 数 组 A 进 行 排 序 , 接 着 取 最 中 间 的 点 即 可 。 因此我们先将数组A进行排序,接着取最中间的点即可。 A

在这里插入图片描述

当 n 为 奇 数 时 , 最 后 将 多 出 一 项 最 中 间 的 点 ∣ A n + 1 2 − x ∣ 未 配 对 , 将 x 设 置 在 点 A n + 1 2 上 是 最 优 解 。 当n为奇数时,最后将多出一项最中间的点|A_{\frac{n+1}{2}}-x|未配对,将x设置在点A_{\frac{n+1}{2}}上是最优解。 nA2n+1x,xA2n+1
在这里插入图片描述

当 n 为 偶 数 时 , 最 中 间 的 分 组 是 ∣ A n 2 − x ∣ + ∣ A n 2 + 1 − x ∣ , 将 x 设 置 在 这 两 点 之 间 ( 包 括 两 点 ) 即 可 。 当n为偶数时,最中间的分组是|A_{\frac{n}{2}}-x|+|A_{\frac{n}{2}+1}-x|,将x设置在这两点之间(包括两点)即可。 nA2nx+A2n+1x,x()

综 上 , 最 短 距 离 就 是 将 所 有 商 店 坐 标 排 序 后 , 两 两 配 对 的 距 离 之 和 ∑ i = 1 n 2 ∣ A n − i + 1 − A i ∣ , 最 小 值 在 仓 库 设 置 在 A n + 1 2 的 点 上 取 到 。 综上,最短距离就是将所有商店坐标排序后,两两配对的距离之和\sum_{i=1}^{\frac{n}{2}}|A_{n-i+1}-A_i|,\\最小值在仓库设置在A_{\frac{n+1}{2}}的点上取到。 i=12nAni+1AiA2n+1

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define inf 0x7fffffff
using namespace std;
const int N=1e5+10;
int n;
int A[N];
ll ans;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        scanf("%d",&A[i]);

    sort(A+1,A+n+1);

    for(int i=1;i<=n/2;i++)
        ans+=(A[n-i+1]-A[i]);

    printf("%lld\n",ans);

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值