题目概述
在一条数轴上有N家商店,它们的坐标分别为 A[1]~A[N]。现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品。为了提高效率,求把货仓建在何处,可以使得货仓到每家商店的距离之和最小。
输入格式
第一行一个整数N,第二行N个整数A[1]~A[N]。
输出格式
一个整数,表示距离之和的最小值。
数据范围与约定
对于100%的数据: N<=100000, A[i]<=1000000
样例输入
input
4
6 2 9 1
output
12
原题: 点这里
思路分析
线性均分纸牌解法: 点这里
环形均分纸牌问题,相当于首尾相邻的线性均分纸牌问题。求解这类问题,我们需要先找到没有发生交换的位置并断开,再用线性均分纸牌来求解。
对于一般的均分纸牌,M人的持牌数、前缀和分别为:
A[1] , S[1]
A[2] , S[2]
… …
A[M] , S[M]
若在第K个人处把环断开,则M人的持牌数、前缀和分别为:
A[K+1] , S[K+1] - S[K]
A[K+2] , S[K+2] - S[K]
… …
A[M] , S[M] - S[K]
A[1] , S[1] - S[K] + S[M]
…
A[K] , S[K] - S[K] + S[M]
即每个位置都减去 S[K]
第 M 个人一定是躺赢的,所以 S[M] = 0
所以所需最少步数为:
其中S是A的前缀和:
那当K取何值时上式最小?
显然将S排序后取中位数作为S[K]就是最优解!
代码
#include<iostream>
using namespace std;
#include<vector>
#include<math.h>
#include<algorithm>
void main()
{
int N;
cin >> N;
long A[1000000];
long a;
for (long i = 0; i < N; i++)
{
cin >> a;
A[i] = a;
}
// 求中位数
sort(A, A + N);
long pos;
if (N % 2)
pos = N / 2 - 1;
else
pos = N / 2;
// 货仓与商店间距离和
long ans = 0;
for (long i = 0; i < N; i++)
ans += abs(A[pos] - A[i]);
cout << ans;
}