士兵排队问题

在一个划分成网格的操场上,n个士兵散乱地站在网格点上。网格点用整数坐标(x,y)表示。士兵们可以沿网格边往上、下、左、右移动一步,但在同一时刻任一网格点上只能有一名士兵。按照军官的命令,士兵们要整齐地列成一个水平队列,即排列成(x,y),(x+1,y),…,(x+n-1,y)。如何选择x和y的值才能使士兵们以最少的总移动步数排成一行。

编程计算使所有士兵排成一行需要的最少移动步数。

题目引自POJ

输入格式:

第1行是士兵数n,1≤n≤10000。接下来n行是士兵的初始位置,每行有2个整数x和y,-10000≤x,y≤10000。

输出格式:

一个数据,即士兵排成一行需要的最少移动步数。

输入样例:

5
1  2
2  2
1  3
3  -2
3  3

输出样例:

8
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
栈限制
8192 KB

因为是在坐标网格内移动,想要移动步数最小,x方向移动的步数和y方向上移动的步数必须满足终点坐标减起始坐标,那么想要求总移动步数最小我们可以把x坐标的移动次数和y坐标的移动次数分别求解然后相加,就能得出最少的总移动步数。

在Y轴上,想要某点到所有y坐标的距离和最小即找一个坐标Y_min,使得sumY=|y0-Y_min| + |y1-Y_min| + |y2-Y_min|....|yn-1-Y_min|。对于Y_min如何寻找,我们可用数学方法解的Y_min就是全体y坐标按照升序排列的中位数。

在X轴上,假设按照升序排列后的x坐标序列为x0、x1、x2......xn-1,最后站好时的x坐标序列为a0、a1、a2......an-1,所以sumX= |x0-a0| + |x1-a1| + |x2-a2|....+| xn-1-an-1|。又因为士兵站好时在x轴上是连续的所以a1=a0+1,a2=a0+2.....an-1=a0+n-2,所以上式可化为sumX= |x0-a0| + |x1-1-a0| + |x2-2-a0|....+| xn-1-(n-1)-a0|此时可以看出x轴上移动最少次数的问题就变成了x0、x1-1、x2-2......xn-1-(n-1)这些点的集合与a0的距离最小值,与Y轴的求解方法类似先进行升序排序,当a0等于排序后的中位数时sumX最小。

代码如下:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int res=0;
    int x[10001]={0},y[10001]={0};
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
        cin>>x[i]>>y[i];
    sort(x,x+n);
    for(int i=0;i<n;i++)
        x[i]=x[i]-i;
    sort(x,x+n);
    sort(y,y+n);
    for(int i=0;i<n;i++)
    {
         res+=abs(y[i]-y[n/2]);
         res+=abs(x[i]-x[n/2]);
    }
    cout<<res<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值