题目大意
已知 N 头牛的位置,问牛舍建在哪里,牛到牛舍的距离和最小(不能建在牛的位置)。
思路
和上一题很类似的中位数求解的变型。约束条件就是牛舍不能建在牛的位置。先抛开约束,那么可以x,y方向分别中位数求解,得最优的位置。这时候看这里是不是牛的位置,如果不是,那么这就是答案。
如果是,考虑往旁边移动,x、y方向仍然可以分开考虑。注意到很关键的一句话:
The hungry cows never graze in spots that are horizontally or vertically adjacent.
也就是,如果当前点是牛的位置,那么其上下左右必定不是。由此,对于x或y方向,如果点的个数是奇数,那么最优点一定是最中间点左边一个或者右边一个,且一定满足约束条件。如果是偶数,那么最优点在中间两个点之间的所有整数点(包括两端点)产生,且至少有一个满足约束条件。分别从 x 方向和 y 方向如此考虑即可。
AC代码
#include<iostream>
#include<algorithm>
#define size_n 10000
#define INF 1000000000
using std::cin;
using std::cout;
using std::sort;
int myabs(int x){
return x > 0 ? x : -x;
}
int main(){
int flag = 0;
int x[size_n], y[size_n];
int ox[size_n], oy[size_n];//保存最初的坐标
int dire[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
int n;
cin>>n;
for(int i = 0; i < n; i++){
cin>>x[i]>>y[i];
ox[i] = x[i];
oy[i] = y[i];
}
sort(x, x + n);
sort(y, y + n);
int mid = n >> 1;
int plan = 0;
int minn = INF;
int ans = 0;
if(n&1){
for(int i = 0; i < n; i++){
if(ox[i] == x[mid] && oy[i] == y[mid]){
flag = 1;
minn = INF;
for(int j = 0; j < 4; j++){
int nx = x[mid] + dire[j][0];
int ny = y[mid] + dire[j][1];
int sum = 0;
for(int k = 0; k < n; k++){
sum += myabs(ox[k] - nx) + myabs(oy[k] - ny);
}
if(sum < minn){
minn = sum;
plan = 1;
}
else if(sum == minn){
plan++;
}
}
break;
}
ans += myabs(x[mid] - ox[i]) + myabs(y[mid] - oy[i]);
plan = 1;
}
if(flag){
cout<<minn<<" "<<plan;
}
else cout<<ans<<" "<<1;
}
else {
minn = 0;
plan = (x[n / 2] - x[n / 2 - 1] + 1) * (y[n / 2] - y[n / 2 - 1] + 1);
for(int i = 0; i < n; i++){
minn += myabs(ox[i] - x[n / 2]) + myabs(oy[i] - y[n / 2]);
if(ox[i] >= x[n / 2 - 1] && ox[i] <= x[n / 2] && oy[i] >= y[n / 2 - 1] && oy[i] <= y[n / 2]){
plan--;
}
}
cout<<minn<<" "<<plan;
}
return 0;
}