算法实验T10——POJ3269 Building A New Barn

题目链接

题目大意

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值