zoukankan      html  css  js  c++  java
  • 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;
    } 
    

      

  • 相关阅读:
    递归与分治4
    递归与分治3
    递归与分治2
    递归与分治1
    枚举与递推3
    枚举与递推2
    求编译器中数的最值(c++)
    移动小球链表实现
    阶乘的精确值
    while((c = getchar()) != EOF)(键盘输入问题)
  • 原文地址:https://www.cnblogs.com/zhumengdexiaobai/p/8511627.html
Copyright © 2011-2022 走看看