POJ 1723 SOLDIERS

原题

Description:

平面直角坐标系中给定n个点, 每一次只能将一个点移动一个单位, 求移动的最小次数使得这n个点位于同一水平线上且全部相邻.

Input:

n:点的个数(1<= n <=10000)

接下来i(1<= i <=n)行每行输入第i个点的横纵坐标, 中间空格隔开. (-10000 <= x[i],y[i] <= 10000)

Output:

最小移动的步数

Solution:

先只考虑纵坐标, 对于最两端的点, 同时移动到点连线内的任意一位置所需的距离相同, 且均小于移动到点连线外任意位置的距离.

对于次两端的点也是如此, 以此类推, 想要达到纵坐标上的移动步数的最小值, 只需将这n个点先排序, 再全部移到中位数的点处.

(假定已经对y[]进行了排序)即 y[0] -> y[n / 2], y[1] -> y[n / 2], ......, y[n - 1] -> y[n / 2]; 步数为∑y[i] - y[n / 2];


再来考虑横坐标, 假定移动完成后横坐标最左边的点坐标为 xx

则需要将(注意:这个时候已经对x[]完成了排序, 原本左边的点最后也在左边) //大概是这么说的吧

x[0] -> xx + 0;

x[1] -> xx + 1;

...

x[n - 1] -> xx + (n - 1);

转换后变成

x[0] - 0 -> xx;

x[1] - 1 -> xx;

...

x[n - 1] - ( n - 1) -> xx;

所需的步数为了 ∑abs(x[i] - i - xx);

所需要做的即是找出xx, 观察到x[i] - i -> xx与纵坐标的形式类似. 可以得出, xx 即为将x[i] - i 重新排序后的中间值.


AC code:

#include<cstdio>  
#include<cstring>  
#include<iostream>  
#include<cstdlib>  
#include<cmath>  
#include<algorithm>  
#include<queue>  
#include<stack>  
#include<set>  
#include<map>
#include<functional>
using namespace std;
int x[10000 + 5], y[10000 + 5];
int _x[10000 + 5];
int main()
{
	int x_steps = 0, y_steps = 0, ans = 0;
	int n;
	scanf("%d", &n);
	for (int i = 0; i < n; i++)
	{
		scanf("%d%d", &x[i], &y[i]);
	}
	sort(x, x + n);
	sort(y, y + n);
	for (int i = 0; i < n; i++)
	{
		_x[i] = x[i] - i;
	}
	sort(_x, _x + n);
	for (int i = 0; i < n; i++)
	{
		y_steps += abs(y[i] - y[n / 2]);
		x_steps += abs(x[i] - i - _x[n / 2]);
	}
	ans = x_steps + y_steps;
	printf("%d\n", ans);
	return 0;
}
最后, WA了很多次, 一直没找到错在哪, 最后把qsort()换成了sort()就过了, 真心求dalao告知这是为什么...


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值