http://pipioj.online/problem.php?id=1018
思路:和这道题很像。既然已知当 x = a [ m i d ] x=a[mid] x=a[mid]时, ∑ i = 1 n ∣ a i − x ∣ \sum_{i=1}^n|a_i-x| ∑i=1n∣ai−x∣取得最小值,那么将所有士兵移动到同一行的纵坐标就确定了。现在考虑横坐标,假设最终结果中第一个士兵的横坐标为 t t t,那么根据贪心策略,我们肯定希望最小的 x i x_i xi移动到 t t t,第二小的 x i x_i xi移动到 t + 1 t+1 t+1……那么对横坐标进行排序后,我们希望求出:
m i n ( ∑ i = 1 n ∣ x i − ( t + i − 1 ) ∣ ) = m i n ( ∑ i = 1 n ∣ ( x i − i + 1 ) − t ∣ ) min(\sum_{i=1}^n|x_i-(t+i-1)|)=min(\sum_{i=1}^n|(x_i-i+1)-t|) min(i=1∑n∣xi−(t+i−1)∣)=min(i=1∑n∣(xi−i+1)−t∣)
令 x i ′ = x i − i + 1 x_i'=x_i-i+1 xi′=xi−i+1,上式可变为: m i n ( ∑ i = 1 n ∣ x i ′ − t ∣ ) min(\sum_{i=1}^n|x_i'-t|) min(∑i=1n∣xi′−t∣),显然当 t = x ′ [ m i d ] t=x'[mid] t=x′[mid]时取得最小值。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1e4+5;
int n,x[maxn],y[maxn];
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
scanf("%d %d",&x[i],&y[i]);
sort(x+1,x+1+n);
for(int i=1;i<=n;i++)
x[i]-=i-1;
sort(x+1,x+1+n);
sort(y+1,y+1+n);
int xmid=x[(n+1)>>1];
int ymid=y[(n+1)>>1];
int cnt=0;
for(int i=1;i<=n;i++)
cnt+=abs(x[i]-xmid)+abs(y[i]-ymid);
printf("%d\n",cnt);
}
return 0;
}