29-街道最短路径问题(哈曼顿距离)

http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=7

            街区最短路径问题

时间限制: 3000 ms  |  内存限制:65535 KB
难度: 4
 
描述
一个街区有很多住户,街区的街道只能为东西、南北两种方向。

住户只可以沿着街道行走。

各个街道之间的间隔相等。

用(x,y)来表示住户坐在的街区。

例如(4,20),表示用户在东西方向第4个街道,南北方向第20个街道。

现在要建一个邮局,使得各个住户到邮局的距离之和最少。

求现在这个邮局应该建在那个地方使得所有住户距离之和最小;

 
输入
第一行一个整数n<20,表示有n组测试数据,下面是n组数据;
每组第一行一个整数m<20,表示本组有m个住户,下面的m行每行有两个整数0<x,y<100,表示某个用户所在街区的坐标。
m行后是新一组的数据;
输出
每组数据输出到邮局最小的距离和,回车结束;
样例输入
2
3
1 1
2 1
1 2
5
2 9 
5 20
11 9
1 1
1 20
样例输出
2
44
来源
经典题目
上传者
iphxer
思路:注意不一定在某个居民点上,但一定在中间。
题目的意思实际上就是让我们求所有点的x到邮局x之和加上所有点的y到邮局y之和的和。
因为距离只计算x轴和Y轴距离之和而不是斜对角线距离,所以可以把x轴距离和y轴距离分开分析计算最短距离,彼此一定不会影响。
以x轴横向点到其他点最短距离为例:问题等价于在X轴有若干点中选取其中一点,使该点到其他点距离和最小。
这个最短距离点一定是排在中间的那个点,比如有5个点,一定选择第3个点;如果有4个点,一定选择第2个点或者第3个点(可以证明选择这两个点任意一个,结果一定相同)
选择中间点的反证法证明:
假设选择非中间点,并认为该点到其他点的距离和最小,大家可以在X轴上画画图算算,一定还可以找到距离和比最小值还小一段距离的点(距离大小为假设最小点到中间点的距离),这和我们假设距离和最小条件矛盾,所以只能选中间点。
方法一:暴力:
#include <iostream>
#include <algorithm> 
using namespace std;
const int INF = 0x3f3f3f3f;

int main(){
	int n, m;
	int a[23], b[23];
	cin >> n;
	while(n--){
		cin >> m;
		for(int i = 0; i < m; i++){
			cin >> a[i] >> b[i];
		}
		int ans = INF, sum = 0;
//		for(int i = 0; i < m; i++){ //遍历所有用户的点 
//			sum = 0;
//			for(int j = 0; j < m; j++){
//				sum += abs(a[i] - a[j]) + abs(b[i] - b[j]);
//			}
//			ans = min(ans, sum);
//		}
		for(int i = 0; i < 100; i++){ //遍历所有可能区间内的点,上面的代码不能通过,可见不一定落在用户位置上 
			for(int j = 0; j < 100; j++){
				sum = 0;
				for(int k = 0; k < m; k++)
					sum += abs(i - a[k]) + abs(j - b[k]);
				ans = min(ans, sum); 
			}
		}
		cout << ans << endl;
	}	
	return 0; 
} 
/*
3
8
1 1
2 1
3 1
1 2
3 2
1 3
2 3
3 3
*/ 

  方法二:找中点

#include <iostream>
#include <algorithm>
using namespace std;

int main(){
	int a[22], b[22];
	int t;
	cin >> t;
	while(t--){
		int m; 
		cin >> m;
		for(int i = 0; i < m; i++){
			cin >> a[i] >> b[i];
		}
		sort(a, a + m);
		sort(b, b + m);
		int ax = a[m / 2];  //ax为所有x排好序的中间那个
		int by = b[m / 2];
		int ans = 0;
		for(int i = 0; i < m; i++)
		 	ans += abs(ax - a[i]) + abs(by - b[i]);
		cout << ans << endl;
	}
	return 0;
} 

  

转载于:https://www.cnblogs.com/zhumengdexiaobai/p/8511627.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值