11. 排兵布阵

目录

题目

思路(贪心+快排)

注意事项 

C++代码


题目

排兵布阵
Description
总所周知,韩信是一位神勇的军事家。某日夜幕,敌方突然来袭,韩信作为塞外将帅吹响紧急的号角。各个帐内的士兵听见号角立即集合,站成一排,排成连续的一队。但是士兵太多了,如果让他们集合耗费太多精力就没有办法打好接下来的胜仗,因此韩信希望选择一个最优的方案使得所有士兵从帐内移动到将要站队的位置的曼哈顿距离和最小!

Input
第一行输入一个整数 n(1 ≤ n ≤ 10^5)表示士兵数量;

接下来 n 行,每行输入两个整数 xi,yi(-10^9 ≤ xi,yi ≤ 10^9)表示第 i 名士兵帐篷的坐标。

Output
请输出一个整数,表示所有士兵从帐内移动到将要站队的位置的距离和。

Hint
站成一排的意思是最终队列中士兵们的纵坐标相同,横坐标排成连续的一段区间。

曼哈顿距离:点(x1,y1)和点(x2,y2)的曼哈顿距离是|x1 - x2| + |y1 - y2|。

答案可能会超过int范围,但保证小于 2 的 64 次方,使用printf输出 64 整数请使用%lld!

测试输入期待的输出时间限制内存限制额外进程
测试用例 1以文本方式显示
  1. 3↵
  2. 0 0↵
  3. 10 10↵
  4. 0 10↵
以文本方式显示
  1. 19↵
1秒64M0

思路(贪心+快排)

数学思想:一组离散数据与它们的中位数的离差绝对值最小(变量值与中位数的离差绝对值之和最小)

 基于上述推论,我们的基本思路如下:

  1. 横坐标和纵坐标互不影响,可以分别构造两个数组存取士兵的x,y,分开单独计算
  2. 对于纵坐标
    先排序;
    然后遍历Y,结果加上Y[n/2]-Y[i]的绝对值。
  3. 对于横坐标
    同样先排序;

    设第一个人站在x时总距离最小,则剩下人根据Xi的大小依次往后站,因为不存在Xi<Xj但i站在j后面的情况;
    距离之和为|X0-x|+|X1- (x+1) |+|X2-(x+2)|+ …… +|Xn-1-(x+(n-1))|
    经过变形得到|(X0-0)-x|+|(X1-1)-x|+|(X2-2)-x|+ …… …… +|(Xn-1-(n-1))-x|;
    此时我们并不知道x的位置;
    因此可以继续优化,Xi - = i(把Xi-i看作整体),对其重新排序;
    最后结果加上X[n/2]-X[i]的绝对值。

注意事项 

  • vector初始化时要定义大小,vector<数据类型> 数组名称(大小),否则它只是一个空数组,在需要使用时只能通过push_back()函数向vector中添加元素。
  • 关于sort函数,它的头文件是algorithm,本题用到的用法是sort(container.begin(), container.end());

    sort函数是C++标准库中的一个排序算法,用于对容器中的元素进行排序。它可以对任何可排序的容器(如数组、向量、列表等)进行排序。

    sort函数的用法如下:

    // 排序整个容器
    sort(container.begin(), container.end());

    // 排序指定范围内的元素
    sort(container.begin() + start, container.begin() + end);

    // 自定义排序规则
    sort(container.begin(), container.end(), compareFunction);
     

    其中,container是要排序的容器,begin和end是要排序的范围,compareFunction是一个可调用对象,用于指定排序规则。

    默认情况下,sort函数使用升序排序,即将容器中的元素按照从小到大的顺序排列。如果要进行降序排序,可以使用`greater`函数对象作为比较函数。

    C++代码

#include <vector>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
int main() {
	int n;
	cin >> n;
    vector<long long> X(n);
    vector<long long> Y(n);
    for (int i = 0; i < n; i++) {
        int x, y;//士兵坐标
        cin >> x >> y;
        X[i] = x;
        Y[i]= y;
    }

    long long res=0;
    sort(Y.begin(), Y.end());
    sort(X.begin(), X.end());
    for (int i = 0; i < n; i++) {
        res += abs(Y[i] - Y[n / 2]);
        X[i] -= i;
    }
    sort(X.begin(), X.end());
    for (int i = 0; i < n; i++) {
        res += abs(X[i] - X[n / 2]);
    }
    cout << res << endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

榆榆欸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值