[USACO07FEB]新牛棚Building A New Barn

# 洛谷题目链接:[[USACO07FEB]新牛棚Building A New Barn](https://www.luogu.org/problemnew/show/P2874)

题目描述

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 (Xi, Yi) (-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 (X, Y) and (Xi, Yi) 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?
给出平面上n个不相邻的点,要求到这n个点的曼哈顿距离之和最小的点的个数ans2,和这个最小距离ans1。

输入输出格式

输入格式:

Line 1: A single integer: N

Lines 2..N+1: Line i+1 contains two space-separated integers which are the grazing location (Xi, Yi) of cow i

输出格式:

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.

输入输出样例

输入样例#1:

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

输出样例#1:

10 4

说明

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).

简述一下题意:给出一个二维平面上(n)个点.要求出(ans2)个点使得这(ans2)个点到所有点的曼哈顿距离之和,这(ans2)个点不能是原平面直角坐标系中给出的点.两点间曼哈顿距离的公式为(left|x-x_i ight|+left|y-y_i ight|).

既然要到所有点的曼哈顿距离之和最小,那么可以先设答案点坐标为((x,y)).可以得到这样一个式子:

[ans1=sum{(left|x-x_i ight|+left|y-y_i ight|)} ]

显然我们是要求出一个((x,y))使得(ans1)最小,因为(x),(y)互不影响,所以可以分开处理,那么根据我们的数学知识,可以得知使(ans1)最小的值就是(x)序列的中位数,同理(y)也是序列中的中位数.

这样我们就求出了(ans1),但是因为题目的限制,如果(n)为奇数时,(x)(y)直接求出的中位数有可能是原图中给出的点.所以这时我们要对这个点的上下左右进行判断,对上下左右求一遍最小值.

如果(n)为偶数时,那么在(x[n/2],x[n/2+1],y[n/2],y[n/2+1])这四个点所围成的矩形中的所有点都是满足条件的. 先计算出这个矩形中包含的点的个数,然后再将原图中包含的点都一个个删掉.

#include<bits/stdc++.h>
using namespace std;
const int inf=2147483647;
const int N=10000+5;

int n, x[N], y[N], ans1 = inf, ans2 = 0;
int dir[]={0,1,0,-1,0};

struct node{
    int x, y;
}p[N];

int gi(){
    int ans = 0 , f = 1; char i = getchar();
    while(i<'0'||i>'9'){if(i=='-')f=-1;i=getchar();}
    while(i>='0'&&i<='9'){ans=ans*10+i-'0';i=getchar();}
    return ans * f;
}

int main(){
    cin >> n;
    for(int i=1;i<=n;i++) x[i] = gi(), y[i] = gi();
    for(int i=1;i<=n;i++) p[i].x = x[i], p[i].y = y[i];
    sort(x+1 , x+n+1); sort(y+1 , y+n+1);
    if(n & 1){
		int a = x[n/2+1], b = y[n/2+1], sum = 0;
		for(int i=1;i<=n;i++)
		    sum += abs(a-x[i])+abs(b-y[i]);
		ans1 = sum; ans2 = 1;
		for(int i=1;i<=n;i++)
		    if(p[i].x == a && p[i].y == b) ans1 = inf;
		for(int i=0;i<4;i++){
		    int nx = a+dir[i], ny = b+dir[i+1], sum = 0;
		    for(int i=1;i<=n;i++)
			sum += abs(nx-x[i])+abs(ny-y[i]);
		    if(sum < ans1) ans1 = sum, ans2 = 1;
		    else if(sum == ans1) ans2++;
		}
	}
    else{
		int x1 = x[n/2], x2 = x[n/2+1];
		int y1 = y[n/2], y2 = y[n/2+1], sum = 0;
		for(int i=1;i<=n;i++)
		    sum += abs(x1-x[i])+abs(y1-y[i]);
		ans1 = min(ans1 , sum);
		ans2 = (x2-x1+1)*(y2-y1+1);
		for(int i=1;i<=n;i++)
		    if(x1<=p[i].x && p[i].x<=x2 && y1<=p[i].y && p[i].y<=y2) ans2--;
    }
    printf("%d %d
",ans1,ans2);
    return 0;
}
原文地址:https://www.cnblogs.com/BCOI/p/8870220.html