算法实验T9——POJ1723 SOLDIERS

题目链接

题目大意

一些士兵站在矩阵的一些方格内,现要把他们移动到一横排,并连续地排成一队,问最少需 要移动多少步。

思路

        先来考虑一个经典的用中位数求解的问题:

数轴上n个点,将他们移到一个相同位置的最小移动距离是多少?

        写成表达式就是求:min(\sum_0^{n-1}|x_i - a|) ,其中a是变化量。当 n 为奇数时,a只能是取最中间那个点的位置(假设取最中间那个点右边相距为 d 的位置,那么有\lfloor n / 2\rfloor + 1个点的花费增加d,有\lfloor n / 2\rfloor个点花费减少d,整体花费增加);n为偶数时,a 可以取中间两个点之间的任何点(包括两端点),证明方法类似。

        这个问题中稍有不同,y方向需要移到同一高度,与上述是一样的,但还需保证x方向连续排列。我们发现,x和y方向的移动互不干扰,可以分开考虑,最终结果是两方向上移动的最小代价直接相加。

        y方向移到某一高度直接用上面的中位数方法求解即可。对于x方向,我们先将点按x坐标(升序)排序,假设最终要移到的连续位置的横坐标值为a_0a_{n-1},是一个公差为1的等差数列。现在就是要把每个点一一对应移到这些位置上,如何一一对应?感觉上,应该是按顺序一一对应,即x_i移到a_i。确实如此,假设先按这种方案移动,使其中两个点的对应的点交换,那么一定会在中间产生一段交叠区域,即多余花费。现在,我们要求的即为|x_0-a_0| + |x_1-a_1| +...+|x_{n-1}-a_{n-1}|的最小值,为了向中位数方法的方向靠近,我们在每个绝对值里提出一个相同的值(因为在可以用中位数方法的问题中,每个绝对值里的被减数是相同的),这里就取a_0,化为|(x_0-0) - a_0| + |(x_1-1) - a_0| +...+|(x_{n-1}-(n-1))-a_0|。由此,我们只需要将每个点的x坐标依次减去0...n-1,就可以用取中位数的方法求解。

AC代码

#include
#include

using std::cin;
using std::cout;
using std::sort;
long long abs(long long a){
	return (a > 0) ? a : -a;
}
int main(){
	long long int x[10000], y[10000];
	int n;
	long long int ans = 0;
	cin>>n;
	for(int i = 0; i < n; i++){
		cin>>x[i]>>y[i];
	}
	sort(y, y + n);
	for(int i = 0; i < n; i++){
		ans += abs(y[i] - y[n>>1]);
	}
	sort(x, x + n);
	for(int i = 0; i < n; i++){
		x[i] -= (long long )i;
	}
	sort(x, x + n);
	for(int i = 0; i < n; i++){
		ans += abs(x[i] - x[n>>1]);
	}
	cout<

 

你可能感兴趣的:(HUST算法实验,算法)