寒假每日一题货仓选址(个人练习)详细题解+推导证明(第一天)

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 1N100000
  • 0 ≤ A i ≤ 40000 0≤A_i≤40000 0Ai40000
输入样例:
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 12+22+22+32+52=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 12.5+22.5+32.5+52.5=5


最后提交,AC😁

推导证明

本题用到的最主要的数学知识是 ∣ x − a ∣ + ∣ x − b ∣ > = ∣ a − b ∣ |x-a| + |x-b| >= |a-b| xa+xb>=ab


通过证明可以看到最优解即中位数。

写法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打卡。

以上是关于寒假每日一题货仓选址(个人练习)详细题解+推导证明(第一天)的主要内容,如果未能解决你的问题,请参考以下文章

寒假每日一题找硬币(个人练习)详细题解+推导证明(第十二天)

寒假每日一题剪绳子(个人练习)详细题解+推导证明(第六天)

寒假每日一题回文平方(个人练习)详细题解+推导证明(第五天)

寒假每日一题红与黑(个人练习)详细题解+推导证明(第四天)

寒假每日一题数字三角形(个人练习)详细题解+推导证明(第二天)

寒假每日一题奖学金(个人练习)详细题解+推导证明(第十天)