P1889 士兵站队 中位数【1】

题目描述  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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值