T2478 軍訓站隊(普及難度)(數論題)
https://www.luogu.org/problem/show?pid=T2478
題目背景
某X去軍訓了,教官比hwh那個還喪病= =
題目描述
在一個划分成網格的操場上,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
一 士兵有多種移動方式
通過適當的移動順序和移動路線可以使得同一時刻不會有兩名士兵站在同一點
二 題目要求最佳移動方式(即求移動的最少步數)
題目要求轉化為求士兵站立的“最終位置”,即如何取“最終位置”使得士兵移動的步數最少(最優)
Y軸方向上的考慮
設目標坐標為M,即n個士兵最終需要移動到的Y軸的坐標值為M
n個士兵的Y軸坐標分別為:
Y0,Y1,Y2 …… …… Yn-1
則最優步數S=|Y0-M|+|Y1-M|+|Y2-M|+ …… …… +|Yn-1-M|
結論:M取中間點的值使得S為最少(最優)
證明:……
從最上和最下的兩個士兵開始遞推……
最優位置
最優位置
歸結到最后,處於中間位置的士兵的Y軸坐標值就是“最終位置”的Y軸坐標
可能有兩種情況
士兵總數為雙數情況:取中間兩點間的任意一個位置
士兵總數為單數情況:取中間點的所在位置
解決辦法:對所有的Y軸坐標進行排序(O(nlogn))或者進行線性時間選擇(O(n))
然后取“中間”點的Y軸坐標值作為最佳位置M的值
最后通過公式求出Y軸方向上移動的最優步數
X軸方向上的考慮
首先需要對所有士兵的X軸坐標值進行排序
然后,按從左至右的順序依次移動到每個士兵所對應的“最終位置”(最優),所移動的步數總和就是X軸方向上需要移動的步數
例,最左的士兵移動到“最終位置”的最左那位,第二個士兵移動到“最終位置”的第二位
則總的步數為:士兵一移動步數+士兵二移動步數+ …… +士兵n移動步數
如何確定X軸方向上的最佳的“最終位置”?
共n個士兵
他們相應的X軸坐標為:X0,X1,X2 …… …… Xn-1
設,士兵需要移動到的“最終位置”的X軸坐標值為:k,k+1,k+2 …… …… k+(n-1)
則所求最優步數S=|X0-k|+|X1- (k+1) |+|X2-(k+2)|+ …… +|Xn-1-(k+(n-1))|
經過變形S=|X0-k|+|(X1-1)-k|+|(X2-2)-k|+ …… …… +|(Xn-1-(n-1))-k|
注意到公式的形式與Y軸方向上的考慮一樣,同樣是n個已知數分別減去一個待定數后取絕對值,然后求和
因此還是采用取中位數的辦法求得k值,最后算出最優解
#include<cstdio> #include<algorithm> using namespace std; int x[10500],y[10500]; int main(){ int n,x1,y1,ans=0; 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]-=i; } sort(x,x+n); x1=x[(n-1)/2];y1=y[(n-1)/2]; for(int i=0;i<n;i++){ ans+=abs(x[i]-x1); ans+=abs(y[i]-y1); } printf("%d",ans); return 0; }