HDU 4311 Meeting point-1

HDU 4311 : Meeting point-1 http://acm.hdu.edu.cn/showproblem.php?pid=4311  

题目大意:给出若干个点,找到一个点,使得所有的点到这个点的曼哈顿距离之和最小,求这个最小的距离即可。

题目误区:找到的这个点,一定要是给定点中的一个,不是给定点中的,虽然能使曼哈顿距离之和最小,但也不满足题意,不可取。所以我们不能只看x,求得其他点距离任意一个点最小的距离。然后再去看y,这样有可能找到的不是最小的距离。

题目分析:由于点的个数比较多,而且坐标的范围也比较大,直接去找肯定会超时,所以,我们采用把x和y暂时分开来找的方法。也算是横向遍历每一个所给出的点,复杂度也就是O(n)。对于x,我们要先对x进行从小到大排序,然后把从x1到xn与x0之间的距离更新在结构体数组中,即结构体数组首位为0,由于我们要求的是最小的距离,所以把累加的距离也放在一个sumx的数组中,并把这样的顺序记录下来。然后同理对y进行同样的操作,之后把其他点到x0点的距离记录下来了。

而对于任意的xi,我们可以在其他点与x0的距离的基础上进行增减,画图解释一下:




代码实现如下:

#include <iostream>
#include <stdio.h>
#include <algorithm>

using namespace std;

const int MAXN=100005;
struct node
{
    long long x,y,id; //由于有两次排序,id用来记录第一次排完序之后的顺序
}point[MAXN];
long long sumx[MAXN],sumy[MAXN]; //分别用来存放从|x1x0|到|xnx0|的距离之和,和从|y1y0|到|yny0|的距离之和

bool cmpx(node a,node b) //按x递增给结构体排序
{
    if(a.x!=b.x)
        return a.x<b.x;
    return a.y<b.y;
}

bool cmpy(node a,node b) //按y递增给结构体排序
{
    if(a.y!=b.y)
        return a.y<b.y;
    return a.x<b.x;
}

int main()
{
    int t,n;
    long long sum;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=0; i<n; i++)
        {
            scanf("%lld%lld",&point[i].x,&point[i].y);
        }

        sort(point,point+n,cmpy);
        sumy[0]=0;
        point[0].id=0;
        for(int i=1; i<n; i++)
        {
            point[i].y=point[i].y-point[0].y;
            sumy[i]=sumy[i-1]+point[i].y;
            point[i].id=i;
        }
        point[0].y=0;

        sort(point,point+n,cmpx);
        sumx[0]=0;
        for(int i=1; i<n; i++)
        {
            point[i].x=point[i].x-point[0].x;
            sumx[i]=sumx[i-1]+point[i].x;
        }
        point[0].x=0;

        sum=sumx[n-1]+sumy[n-1];
        for(int i=1; i<n; i++)
        {
            long long ans= i * point[i].x - sumx[i-1] + sumx[n-1] - sumx[i] - (n - i - 1) * point[i].x;
            ans+=(point[i].id*point[i].y-sumy[point[i].id-1]+sumy[n-1]-sumy[point[i].id]-(n-point[i].id-1)*point[i].y);
            if(ans<sum)
            {
                sum=ans;
            }
        }
        printf("%lld\n",sum);
    }
    return 0;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值