來自PTA的一道習題:
在一個划分成網格的操場上,n個士兵散亂地站在網格點上。網格點用整數坐標(x,y)表示。士兵們可以沿網格邊往上、下、左、右移動一步,但在同一時刻任一網格點上只能有一名士兵。按照軍官的命令,士兵們要整齊地列成一個水平隊列,即排列成(x,y),(x+1,y),…,(x+n-1,y)。如何選擇x和y的值才能使士兵們以最少的總移動步數排成一行。
編程計算使所有士兵排成一行需要的最少移動步數。
輸入格式:
第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
思路:
X軸和Y軸可以分開考慮。
士兵y軸坐標不變,可以假想為有一條垂直於y軸的直線,所有士兵都要移動到這條直線上,顯然這是一個求中位數Y的問題。解決方法為將士兵y軸坐標排序,求得中位數后求各士兵y軸坐標據其的距離abs(y[i] - Y)
(排序不需要寫了吧,我這里用的是快排
至此,在我們的假設中所有士兵已經移動到了同一水平線上,那么x軸的呢……有了y軸的思路,x軸應該也比較容易想到,它仍是一個求中位數的問題。
我們先對士兵x軸坐標進行排序,假設排序完他們坐標x0,x1,x2……x(n - 1),而最終坐標為x,x+1,x+2……x+(n - 1),那么移動步數也就是(x0 - x) + (x1 - x -1) + …… + (x(n - 1) - x - n)= (x0 - x) + ((x1 - 1) - x) + ((x2 - 2) - x) + …… + ((x(n - 1) - (n - 1) - x) 現在它已經轉化為了求 x0,x1 - 1,x2 - 2……x(n - 1) - (n - 1)的中位數了
OK!上代碼!
#include <stdio.h>
#include <math.h>
int x[10000], y[10000], s[10000];
void quickSort(int l, int r, int *data)
{
if(l >= r) return;
int m = data[(l + r) / 2];//中間的那個
int i = l;
int j = r;
while(i <= j)
{
while(data[i] < m)
i++;
while(data[j] > m)
j--;
if(i <= j)
{//交換
int tmp = data[i];
data[i] = data[j];
data[j] = tmp;
i++;
j--;
}
}//循環結束表示一趟已執行完
if(l < j)
quickSort(l, j, data);
if(r > i)
quickSort(i, r, data);
}
int main()
{
int n, X, Y;
int res = 0;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d", &x[i]);
scanf("%d", &y[i]);
}
//Y軸方向上的考慮
quickSort(0, n - 1, y);
if(n % 2)
Y = y[(n - 1) / 2];
else Y = (y[n / 2] + y[n / 2 - 1]) / 2;
for(int i = 0; i < n; i++)
{
res += abs(y[i] - Y);
}
//X軸方向上的考慮
quickSort(0, n - 1, x);
for (int i = 0; i < n; i++)
{
s[i] = x[i] - i;
}
quickSort(0, n - 1, s);
if(n % 2)
X = s[(n - 1) / 2];
else X = (s[n / 2] + s[n / 2 - 1]) / 2;
for(int i = 0; i < n; i++)
{
res += abs(s[i] - X);
}
printf("%d", res);
return 0;
}
