寒假每日一题货仓选址(个人练习)详细题解+推导证明(第一天)
Posted 我是管小亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了寒假每日一题货仓选址(个人练习)详细题解+推导证明(第一天)相关的知识,希望对你有一定的参考价值。
文章目录
前言
突然发现自己好久没有更博客了,就写一个寒假每日一题来坚持坚持把,不是软广,不是硬广,只是个人练习,题目来自《算法竞赛进阶指南》,模板题。
题目
在一条数轴上有 N N N 家商店,它们的坐标分别为 A 1 A_1 A1~ A N A_N AN。
现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品。
为了提高效率,求把货仓建在何处,可以使得货仓到每家商店的距离之和最小。
输入格式
- 第一行输入整数 N N N。
- 第二行 N N N 个整数 A 1 A_1 A1~ A N A_N AN。
输出格式
- 输出一个整数,表示距离之和的最小值。
数据范围
- 1 ≤ N ≤ 100000 1≤N≤100000 1≤N≤100000
- 0 ≤ A i ≤ 40000 0≤A_i≤40000 0≤Ai≤40000
输入样例:
4
6 2 9 1
输出样例:
12
详细题解
写法1 O ( n l o g n ) O(nlogn) O(nlogn)
#include <iostream>
#include <algorithm>
using namespace std;
const int MaxN = 1000005;
int N;
int A[MaxN];
int main()
cin >> N;
for (int i = 0; i < N; ++i) cin >> A[i];
sort(A, A + N);
// 调试
// for (int i = 0; i < N; ++i) cout << A[i] << " ";
// cout << endl;
int ans = 0;
for (int i = 0; i < N; ++i) ans += abs(A[i] - A[N >> 1]);
cout << ans << endl;
return 0;
通过调试代码,假设输入五个数,计算距离和的最小值,可以发现其实就是中位数到各个位置的距离之和。具体地,首先先对数组进行排序,可以发现是奇数个数,中位数即最中间的数——2,那么距离和即 ∣ 1 − 2 ∣ + ∣ 2 − 2 ∣ + ∣ 2 − 2 ∣ + ∣ 3 − 2 ∣ + ∣ 5 − 2 ∣ = 5 |1-2| + |2-2| + |2-2| + |3-2| + |5-2| = 5 ∣1−2∣+∣2−2∣+∣2−2∣+∣3−2∣+∣5−2∣=5。
偶数也是一样,
∣
1
−
2.5
∣
+
∣
2
−
2.5
∣
+
∣
3
−
2.5
∣
+
∣
5
−
2.5
∣
=
5
|1-2.5| + |2-2.5| + |3-2.5| + |5-2.5| = 5
∣1−2.5∣+∣2−2.5∣+∣3−2.5∣+∣5−2.5∣=5。
最后提交,AC😁
推导证明
本题用到的最主要的数学知识是 ∣ x − a ∣ + ∣ x − b ∣ > = ∣ a − b ∣ |x-a| + |x-b| >= |a-b| ∣x−a∣+∣x−b∣>=∣a−b∣,
通过证明可以看到最优解即中位数。
写法2 O ( n l o g n ) O(nlogn) O(nlogn)
#include <iostream>
#include <algorithm>
using namespace std;
const int MaxN = 1000005;
int N;
int A[MaxN];
int main()
cin >> N;
for (int i = 0; i < N; ++i) cin >> A[i];
sort(A, A+N);
int ans = 0;
// for (int i = 0; i < N; ++i) ans += abs(A[i] - A[N >> 1]);
for (int i = 0; i < N; ++i) ans += A[i] - A[i >> 1]; // 改动位置
cout << ans << endl;
return 0;
最后提交,AC😁
推导证明
解法2与解法1的本质是一样的,同时还能去掉绝对值,因为
A
[
i
]
>
=
A
[
i
/
2
]
A[i] >= A[i/2]
A[i]>=A[i/2]。
写法3 O ( n ) O(n) O(n)
#include <iostream>
#include <algorithm>
using namespace std;
const int MaxN = 1000005;
int N;
int A[MaxN];
int main()
cin >> N;
for (int i = 0; i < N; ++i) cin >> A[i];
// sort(A, A+N);
nth_element(A, A + N/2, A + N); // 改动位置
int ans = 0;
for (int i = 0; i < N; ++i) ans += abs(A[i] - A[N >> 1]);
cout << ans << endl;
return 0;
最后提交,AC😁
推导证明
解法3改进了时间复杂度,从 O ( n l o g n ) O(nlogn) O(nlogn) 变成了 O ( n ) O(n) O(n),相当于去掉了快速排序算法的迭代过程,只是一个随机选择的代码。
下面以一个快排代码为例,整个代码的时间复杂度是 O ( n l o g n ) O(nlogn) O(nlogn),其中随机选择的时间复杂度是 O ( n ) O(n) O(n),递归的时间复杂度是 O ( l o g n ) O(logn) O(logn)。
int partition(vector<int> &data, int start, int end)
int index = (rand()%(end-start+1))+start;
swap(data[index], data[start]);
int pivot = data[start];
int left=start,right=end;
while(left!=right)
while(left<right && data[right]>=pivot)right--;
while(left<right && data[left]<=pivot)left++;
if(left<right) swap(data[left], data[right]);
swap(data[left], data[start]);
return left;
void quicksort(vector<int> &data, int start, int end)
if(start==end) return;
if(start<end)
int index = partition(data,start,end);
quicksort(data,start,index-1);
quicksort(data,index+1,end);
举一反三
可以从一维空间扩展到多维空间。
总结
继续努力,坚持更新,1st打卡。
以上是关于寒假每日一题货仓选址(个人练习)详细题解+推导证明(第一天)的主要内容,如果未能解决你的问题,请参考以下文章
寒假每日一题找硬币(个人练习)详细题解+推导证明(第十二天)
寒假每日一题回文平方(个人练习)详细题解+推导证明(第五天)