题意: 已知 N 头牛的位置,问牛舍建在哪里,牛到牛舍的距离和最小以及可以取到最小值点的个数。
分析:
此题关键点:没有两个放牧点是相邻的
曼哈顿距离公式:d=|x1−x2|+|y1−y2|,由于两点曼哈顿距离的特性,单独求 x 与单独求 y 互不影响
因此,题目即为求 |x−x1|+|x−x2|+…+|x−xn| 的最小值,求 |y−y1|+|y−y2|+…+|y−yn| 的最小值,直接求两者中位数即可。
接对 x、y 各自进行排序比较:
1)当n为奇数时,取( x[n/2+1],y[n/2+1] )
若该点为给出的放牧点,枚举它的上下左右四个方向上的点能求的最小的 d,然后统计当且仅当这4个点的方案数;
若该点不为给出点,则直接记录最小距离,方案数为1。
2)当n为偶数时,取( x[n/2],y[n/2] )和( x[n/2+1],y[n/2+1] )
由曼哈顿距离的特性知:共有( x[n/2+1]−x[n/2]+1)*( y[n/2+1]−y[n/2]+1)个点,且它们到给定的n个点的曼哈顿距离和d相等。
因此枚举每个点是否为给出的放牧点,求一次最小距离,统计可行点的个数即可
#include<iostream>
#include<algorithm>
using namespace std;
#define size 10010 //2 <= N <= 10000
#define INF 0x3f3f3f3f
int x[size];
int y[size];
int original_x[size];
int original_y[size];
int minn,plan; //记录最小值和方案数
int dx[4] = { 1,-1,0,0 };
int dy[4] = { 0,0,1,-1 };
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> x[i] >> y[i];
original_x[i] = x[i];
original_y[i] = y[i];
}
sort(x, x + n);
sort(y, y + n);
if (n % 2 == 1) { // 如果n是奇数
int middle = n / 2;
for (int i = 0; i < n; i++) {
if (x[middle] == original_x[i] && y[middle] == original_y[i]) { //如果为给出的放牧点
minn = INF;
for (int j = 0; j < 4; j++) { //枚举四个方向上的点
int temp_x = x[middle] + dx[j];
int temp_y = y[middle] + dy[j];
int temp_minn = 0;
for (int k = 0; k < n; k++) {
temp_minn += abs(temp_x - x[k]) + abs(temp_y - y[k]);
}
if (temp_minn < minn) {
minn = temp_minn;
plan = 1;
}
else if (temp_minn == minn)
plan++;
}
break;
}
minn += abs(x[middle] - x[i]) + abs(y[middle] - y[i]);
plan = 1;
}
}
else { //如果n是偶数
int middle1 = n / 2 - 1;
int middle2 = n / 2;
plan = (x[middle2] - x[middle1] + 1)*(y[middle2] - y[middle1] + 1);
for (int i = 0; i < n; i++) {
minn += abs(x[middle1] - x[i]) + abs(y[middle1] - y[i]); //随便选一个区域内的点都行,因为在这个区域内的最小值相同
if (original_x[i] <= x[middle2] && original_x[i] >= x[middle1] && original_y[i] <= y[middle2] && original_y[i] >= y[middle1])
plan--;
}
}
cout << minn << " " << plan << endl;
return 0;
}