【9209】士兵站队问题

Time Limit: 10 second
Memory Limit: 2 MB

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

Input

由文件 input.txt 提供输入数据。文件的第1行是士兵数n,1≤n≤10000。 接下来n行是士兵的初始位置,每行2个整数x和y,-10000≤x,y≤10000。

Output

将计算结构输出到文件output.txt.文件的第一行中的数是士兵排成一行需要的最 少步数。

Sample Input

3
-4 -3
-4 5
5 2

Sample Output

16

【题解】

首先。要让这些士兵都站到同一行。

先对y坐标进行排序。

然后对于它们最后要站的行号k;

S=|a[1].y-k|+|a[2].y-k|+...+|a[n].y-k|;

要让S最小。

想想都能知道k是a[1..n].y的中位数。

答案累加上|a[i]-k|;

这样这些士兵就全都在一行上了。这个问题被转化为一个一维的问题了

然后是在列上的位置。

我们同样对a[i].x进行升序排序。

然后我们可以确定a[1].x,a[2].x,a[3].x。。。。a[n].x

这些位置上的士兵对应最后答案的k,k+1,k+2...k+n-1这些位置。

因为凭感觉就能知道这样比较优。(难道a[n].x还要对应k吗??);

然后S=|a[1].x-k|+|a[2].x-(k+1)|+|a[3].x-(k+2)|...+|a[n].x-(k+n-1)|;

同样要让S最小。

我们把S的表达式做一些改变。

S=|a[1].x-k|+|(a[2].x-1)-k|+|(a[3].x-2)-k|+...+|(a[n].x-(n-1))-k|

然后我们令b[i] = a[i].x-i+1;

S=|b[1]-k|+|b[2]-k|+...+|b[n]-k|;

没错。这又变成求y轴的方法了。

获得b数组之后再对b数组进行一次升序的排序。

然后获得中位数k,再累加|b[i]-k|即可。

这里可以不用再定义一个b数组,直接在a数组的基础上处理一下就好即-i+1;

只有一维的x坐标的情况。你可以理解为。就是把k+1,k+2..k+n-1这些位置全部都移到

了k这个位置。然后本来要在k+1的人,先减去1然后再移到k时就相当于移到k+1了。

本来要在k+2的人同理。

【代码】

#include <cstdio>
#include <algorithm>

using namespace std;

struct point //用于储存输入的点
{
	int x, y;
};

int n, ans = 0;
point a[10001 + 100]; //开大点没关系的。

void input_data() 
{
	scanf("%d", &n); //输入n个士兵的位置。
	for (int i = 1; i <= n; i++)
		scanf("%d%d", &a[i].x, &a[i].y);
}

int cmp1(const point &a, const point &b) //比较函数1,这是y轴的
{
	if (a.y < b.y)
		return 1;
	return 0;
}

int cmp2(const point &a, const point &b) //这是x轴上的。
{
	if (a.x < b.x)
		return 1;
	return 0;
}

int abs(int x) //获取一个数的绝对值。
{
	return x < 0 ? -x : x;
}

void get_ans1()
{
	int mid = a[(n + 1) / 2].y; //这是竖直方向上的k值。
	for (int i = 1; i <= n; i++) //累加即可得到S;
	{
		ans += abs(a[i].y - mid);
		a[i].y = mid; //这一步没有意义,但是能让思路更清晰。表示全都在一行上面了。
	}
}

void get_ans2() //这是x轴上的一维情况
{
	for (int i = 1; i <= n; i++) //先减去i再加上1.
		a[i].x = a[i].x - i + 1;
	sort(a + 1, a + 1 + n, cmp2); //相当于给b数组排序。
	int mid = a[(n + 1) / 2].x; //同样获取k。
	for (int i = 1; i <= n; i++)//累加a[i].x-k的绝对值即可。
		ans += abs(a[i].x - mid);
}

void output_ans()
{
	printf("%d
", ans); //最后输出答案。
}

int main()
{
	input_data();
	sort(a + 1, a + 1 + n, cmp1);//对y坐标进行排序
	get_ans1();
	sort(a + 1, a + 1 + n, cmp2);//对x坐标进行升序排
	get_ans2();
	output_ans();
	return 0;
}



原文地址:https://www.cnblogs.com/AWCXV/p/7632317.html