洛谷 P10452 货仓选址 题解

题目

题目描述

在一条数轴上有 N N N 家商店,它们的坐标分别为 A 1 ∼ A N A_1 \sim A_N A1AN

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

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

输入格式

第一行输入整数 N N N

第二行 N N N 个整数 A 1 ∼ A N A_1 \sim A_N A1AN

输出格式

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

样例 #1

样例输入 #1

4
6 2 9 1

样例输出 #1

12

提示

数据保证, 1 ≤ N ≤ 100000 1 \le N \le 100000 1N100000 0 ≤ A i ≤ 40000 0 \le A_i \le 40000 0Ai40000

做法

首先,如果设最后选择的地址为 x x x ,那么距离和为
∣ a 1 − x ∣ + ∣ a 2 − x ∣ + ∣ a 3 − x ∣ + . . . + ∣ a n − x ∣ |a_1 - x| + |a_2 - x| + |a_3 - x| + ... + |a_n - x| a1x+a2x+a3x+...+anx
其次,我们把这个式子两两分组,分 n n n 为奇数和偶数两种情况看

n n n 为奇数时

原式
= ( ∣ a 1 − x ∣ + ∣ a n − x ∣ ) + ( ∣ a 2 − x ∣ + ∣ a n − 1 − x ∣ ) + . . . + ( ∣ a ( n + 1 ) / 2 − 1 − x ∣ + ∣ a ( n + 1 ) / 2 + 1 − x ∣ ) + ∣ a ( n + 1 ) / 2 − x ∣ = (|a_1 - x| + |a_n - x|) + (|a_2 - x| + |a_{n - 1} - x|) + ... + (|a_{(n + 1) / 2 - 1} - x| + |a_{(n + 1) / 2 + 1} - x|) + |a_{(n + 1) / 2} - x| =(a1x+anx)+(a2x+an1x)+...+(a(n+1)/21x+a(n+1)/2+1x)+a(n+1)/2x
上面的式子的最小值为 ( a n − a 1 ) + ( a n − 1 − x ) + . . . + ( a ( n + 1 ) / 2 + 1 − a ( n + 1 ) / 2 − 1 ) + 0 (a_n - a_1) + (a_{n - 1} - x) + ... + (a_{(n + 1) / 2 + 1} - a_{(n + 1) / 2 - 1}) + 0 (ana1)+(an1x)+...+(a(n+1)/2+1a(n+1)/21)+0 ,也就是说,上面的式子的值不会小于这个式子。
我们发现,当 x x x a ( n + 1 ) / 2 a_{(n + 1) / 2} a(n+1)/2 时与上面的式子的最小值相等,所以此时最小。

n n n 为偶数时

原式
= ( ∣ a 1 − x ∣ + ∣ a n − x ∣ ) + ( ∣ a 2 − x ∣ + ∣ a n − 1 − x ∣ ) + . . . + ( ∣ a n / 2 − x ∣ + ∣ a n / 2 + 1 − x ∣ ) = (|a_1 - x| + |a_n - x|) + (|a_2 - x| + |a_{n - 1} - x|) + ... + (|a_{n / 2} - x| + |a_{n / 2 + 1} - x|) =(a1x+anx)+(a2x+an1x)+...+(an/2x+an/2+1x)
上面的式子的最小值为 ( a n − a 1 ) + ( a n − 1 − x ) + . . . + ( a n / 2 + 1 − a n / 2 ) (a_n - a_1) + (a_{n - 1} - x) + ... + (a_{n / 2 + 1} - a_{n / 2}) (ana1)+(an1x)+...+(an/2+1an/2),也就是说,上面的式子的值不会小于这个式子。
我们发现,当 x x x a n / 2 a_{n / 2} an/2 a n / 2 + 1 a_{n / 2 + 1} an/2+1 之间时与上面的式子的最小值相等,所以此时最小。

代码实现

在c ++ 中,除法是下取整的,因此 n n n 为奇数时 ( n + 1 ) / 2 = n / 2 + 1 (n + 1) / 2 = n / 2 + 1 (n+1)/2=n/2+1 ,也就是说,在c ++ 中, n n n 为奇数时, x x x n / 2 + 1 n / 2 + 1 n/2+1 时最小,而偶数时取 n / 2 + 1 n / 2 + 1 n/2+1 也是一种最小的情况,所以奇数和偶数可以放在一起求。把 a a a 读入后排序,取 a n / 2 + 1 a_{n / 2 + 1} an/2+1 x x x ,求一遍 ∣ a 1 − x ∣ + ∣ a 2 − x ∣ + ∣ a 3 − x ∣ + . . . + ∣ a n − x ∣ |a_1 - x| + |a_2 - x| + |a_3 - x| + ... + |a_n - x| a1x+a2x+a3x+...+anx 即可。

n为奇数时和n为偶数时的不同情况

代码

#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 100010;

int n,a[N];

int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
	sort(a + 1, a + 1 + n);
	int ans = 0;
	for(int i = 1; i <= n; i ++ ) ans += abs(a[i] - a[n/2+1]);
	printf("%d\n", ans);
	return 0;
}

结语

想不出做法时,可以先把答案的式子表示出来,有时问题就能迎刃而解。

  • 19
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值