【POJ 3269】Building A New Barn

本文探讨了一道经典的算法问题:如何确定新建农场的位置以最小化其与各牧区之间的曼哈顿距离之和。通过分析和代码实现,展示了如何解决这类问题,并给出了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Building A New Barn
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 1773 Accepted: 571

Description

After scrimping and saving for years, Farmer John has decided to build a new barn. He wants the barn to be highly accessible, and he knows the coordinates of the grazing spots of all N (2 ≤ N ≤ 10,000 cows. Each grazing spot is at a point with integer coordinates (XiYi) (-10,000 ≤ Xi ≤ 10,000; -10,000 ≤ Yi ≤ 10,000). The hungry cows never graze in spots that are horizontally or vertically adjacent.

The barn must be placed at integer coordinates and cannot be on any cow's grazing spot. The inconvenience of the barn for any cow is given the Manhattan distance formula | X - Xi | + | Y - Yi|, where (XY) and (XiYi) are the coordinates of the barn and the cow's grazing spot, respectively. Where should the barn be constructed in order to minimize the sum of its inconvenience for all the cows?

Input

Line 1: A single integer:  N 
Lines 2.. N+1: Line  i+1 contains two space-separated integers which are the grazing location ( XiYi) of cow  i

Output

Line 1: Two space-separated integers: the minimum inconvenience for the barn and the number of spots on which Farmer John can build the barn to achieve this minimum.

Sample Input

4
1 -3
0 1
-2 1
1 -1

Sample Output

10 4

Hint

The minimum inconvenience is 10, and there are 4 spots that Farmer John can build the farm to achieve this: (0, -1), (0, 0), (1, 0), and (1, 1).

Source

 
很坑爹的一题。
根据题目我们可以知道,就是求一点到其它点的曼哈顿距离总和最小值以及解的个数。
那么我们要知道任意两个点都可以形成一个矩形(也有可能是一条直线),那么这个矩形内任意点到这两个点的曼哈顿距离最小,并且等于这两个点的曼哈顿距离。
而且题目也给出了任意两个点都不相邻,这更是说明了符合上述条件后一定会有解。
其实就是求矩形的交集。(偶数个点)这个问题交给大家思考。
奇数个点的情况要稍微复杂,我们先排出最中间的那个点,然后按上述方法求解,加判断即可。
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

struct Vertex
{
    int x, y;
}v[10005];

int n, left, right, up, down, mid, cost;

bool cmp1(Vertex A, Vertex B)
{
    return (A.x < B.x || (A.x == B.x && A.y < B.y));
}

bool cmp2(Vertex A, Vertex B)
{
    return A.y < B.y;
}

int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; ++i) scanf("%d%d", &v[i].x, &v[i].y);
    sort(v, v + n, cmp1);
    mid = n >> 1;
    left = v[mid - 1].x;
    right = v[mid + (n & 1)].x;
    sort(v, v + (n >> 1), cmp2);
    sort(v + (n >> 1) + (n & 1), v + n, cmp2);
    cost = 0;
    int l = 0, r = n - 1;
    up = 10005;
    down = -10005;
    while (l < r)
    {
        cost += abs(v[l].x - v[r].x) + abs(v[l].y - v[r].y);
        up = min(up, max(v[l].y, v[r].y));
        down = max(down, min(v[l].y, v[r].y));
        l++;
        r--;
    }
    if (n & 1)
    {
            int f = 4;
            if (v[mid].x >= left && v[mid].x <= right && v[mid].y >= down && v[mid].y <= up)
            {
                if (v[mid].x == left) f--;
                if (v[mid].x == right) f--;
                if (v[mid].y == up) f--;
                if (v[mid].y == down) f--;
                printf("%d %d\n", cost + 1, f);
            }
            else
            {
                if (down > v[mid].y)
            {
                cost += down - v[mid].y;
                if (left == v[mid].x || right == v[mid].x) cost++;
                printf("%d 1\n", cost);
            }
            else
                if (up < v[mid].y)
                {
                    cost += v[mid].y - up;
                    if (left == v[mid].x || right == v[mid].x) cost++;
                    printf("%d 1\n", cost);
                }
            }
    }
    else
    {
        int del = 0;
        for (int i = 0; i < n; ++i)
            if (left <= v[i].x && right >= v[i].x && down <= v[i].y && up >= v[i].y)
                del++;
        printf("%d %d\n", cost, (right - left + 1) * (up - down + 1) - del);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/albert7xie/p/4840887.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值