【P1889 士兵站队】(洛谷)

题目描述

在一个划分成网格的操场上,n个士兵散乱地站在网格点上,由整数坐标 (x,y)表示。

士兵们可以沿网格边上、下、左、右移动一步,但在同时刻任一网格点上只能有 1 名士兵。

按照军官的命令,们要整齐地列成个水平队列,即排成队列,即排成 (x,y),(x+1,y), …,(x+n-1,y)。请求出如何选择 x 和 y 的值才能使士兵们以最少的总移动步数排成一列。

输入格式

输入的第一行是一个整数,代表士兵数 n。

第 2 到 (n + 1) 行,每行 2 个整数,第 (i + 1) 行的整数 xi​,yi​ 代表第 i 个士兵的坐标。

输出格式

输出一行一个整数,代表答案。

输入输出样例

输入 #1

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

输出 #1

8

说明/提示

对于 100% 的数据,保证 1≤n≤10000,−10000≤x,y≤10000。

题目分析

        该题目可以理解为首先确定纵坐标 y 的位置,将所有士兵都放在一排上,然后再具体调整横坐标 x 的位置,因此,仅需要计算所有士兵分别在 x 轴方向的移动步数以及在 y 轴方向上的移动步数,最后再将二者相加,即可得到最终的答案。

具体实现步骤

        首先对所有士兵的纵坐标 y 进行 sort 升序排序,然后取纵坐标 y 的中位数,这样就可以知道将士兵们移动到哪一纵坐标处所需要在 y 轴方向移动的步数最少,计算 y 轴方向移动总步数。

        接下来便是计算士兵在 x 轴方向的移动步数,这里我是遍历循环,分别将最左边的士兵放在初始位置位于中间的士兵的 x 坐标减去 n 处,到将最左边的士兵放在初始位置位于中间的士兵的 x 坐标加上 n / 2 处,计算不同方案的士兵在 x 轴方向的移动总步数的最小值。

        最后将二者的步数加在一起,便是答案所得

AC代码及注释

#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
const int N = 1e4 + 10;
int x[N],y[N];
int main()
{
	int n;
	int step = 0;     //定义step变量用于计算移动步数 
	int m_count = 0; 
	cin >> n;         //输入士兵人数 n 
	for(int i = 0;i < n;i ++)
	{
		cin >> x[i] >> y[i];    //依次输入每一个士兵的横纵坐标 
	}
	sort(x,x + n);   //将士兵位置的横坐标排序 
	sort(y,y + n);   //将士兵位置的纵坐标排序 
	int y_mid , x_mid;
	x_mid = x[n / 2];   //计算横坐标中位数 
	y_mid = y[n / 2];   //计算纵坐标中位数 
	for(int i = 0;i < n;i ++)
	{
		step += fabs(y[i] - y_mid);  //将每一个士兵进行 y 轴方向的移动 
	}
	for(int i = x_mid - n;i < x_mid + n/2;i ++)
	{
		int count = 0;
		int k = i;
		for(int j = 0;j < n;j ++)
		{
			count += fabs(x[j] - k);  //计算士兵 x 轴方向的移动步数 
			k ++;
		}
		if(i == x_mid - n) m_count = count;
		if(count < m_count) m_count = count;  //取移动步数最小值 
	}
	step += m_count;  //将 x 轴方向以及 y 轴方向的移动步数相加 
	cout << step;     //输出答案总移动步数 
	return 0;
}

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值