题目描述 https://www.luogu.org/problemnew/show/P1889
在一个划分成网格的操场上, 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 。
输出格式:
只有一个整 数是士兵排成一行需要的最少移动步。
输入输出样例
输入样例#1:复制
5
1 2
2 2
1 3
3 -2
3 3
输出样例#1:复制
8
方法1 我的穷举法 90分,另外超时
#include<iostream>
#include<cstdio>
#include <climits>
#include <algorithm>
#include <cmath>
using namespace std;
int main()
{
int a[10000],b[10000];
int n;
cin>>n;
int rowl=INT_MAX,rowr=-INT_MAX;
int col=INT_MAX,cor=-INT_MAX;
for(int i=0;i<n;i++ )
{
scanf("%d%d",&a[i],&b[i]);
rowl=min(a[i],rowl);
rowr=max(a[i],rowr);
col=min(b[i],col);
cor=max(b[i],cor);
}
int imin1=INT_MAX;
for(int i=col;i<=cor;i++)
{
int y=i,sum=0;
for(int j=0;j<n;j++)
{
sum+=abs(b[j]-y);
}
imin1=min(sum,imin1);
}
sort(a,a+n);
int imin2=INT_MAX;
for(int i=rowl-n;i<=rowr+n;i++)
{
int y=i,sum=0;
for(int j=0;j<n;j++)
{
sum+=abs(a[j]-y-j);
}
imin2=min(sum,imin2);
}
cout<<imin1+imin2<<endl;
}
高级方法,这里关键是求一个坐标x,是的 所有的n项|xi-x|之和最小。实际上这个x就是中位数。
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<string>
#include<cstdio>
#include<cmath>
using namespace std;
int x[1000001],y[1000001];
int main()
{
int n,zb1,zb2,total=0;
cin>>n;
for(int i=1;i<=n;i++)
cin>>x[i]>>y[i]; //输入。
sort(x+1,x+(n+1));
sort(y+1,y+(n+1)); //排序。
for(int i=1;i<=n;i++)
x[i]-=i; //由于士兵要站一排,所以要减不同的。
sort(x+1,x+(n+1)); //剪完还要再排。
if(n%2==0) //接下来就与输油管道一样区中位数。
{
zb1=(x[n/2]+x[n/2+1])/2;
zb2=(y[n/2]+y[n/2+1])/2;
}
else
{
zb1=x[n/2+1];
zb2=y[n/2+1];
}
for(int i=1;i<=n;i++)
{
total+=abs(zb1-x[i])+abs(zb2-y[i]);
}
cout<<total<<endl; //打印。
return 0;
}