POJ 3269 Building A New Barn

题意: 已知 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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值