
剑指Offer——网易笔试之解救小易——曼哈顿距离的典型应用
前言
首先介绍一下曼哈顿,曼哈顿是一个极为繁华的街区,高楼林立,街道纵横,从A地点到达B地点没有直线路径,必须绕道,而且至少要经C地点,走AC和 CB才能到达,由于街道很规则,ACB就像一个直角3角形,AB是斜边,AC和CB是直角边,根据毕达格拉斯(勾股)定理,或者向量理论,都可以知道用AC和CB可以表达AB的长度。
在早期的计算机图形学中,屏幕是由像素构成,是整数,点的坐标也一般是整数,原因是浮点运算很昂贵,很慢而且有误差,如果直接使用AB的距离,则必须要进行浮点运算,如果使用AC和CB,则只要计算加减法即可,这就大大提高了运算速度,而且不管累计运算多少次,都不会有误差。因此,计算机图形学就借用曼哈顿来命名这一表示方法。
曼哈顿距离:两点在南北方向上的距离加上在东西方向上的距离,即d(i,j)=|xi-xj|+|yi-yj|。对于一个具有正南正北、正东正西方向规则布局的城镇街道,从一点到达另一点的距离正是在南北方向上旅行的距离加上在东西方向上旅行的距离。
通过分析下面的题目,可知其可以应用曼哈顿距离计算至(1,1)点最近的点,依据曼哈顿距离即可计算出结果值。若不明白曼哈顿的定义及应用,通过画图观察,其实也可以得到答案。显然若之前就明白曼哈顿距离的定义及应用,问题手到擒来!
代码如下:
package cn.edu.ujn.nk; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Scanner; import java.util.regex.Pattern; public class SaveXiaoYi { /** * 2016-08-09 --02 * 解救小易 有一片1000*1000的草地,小易初始站在(1,1)(最左上角的位置)。小易在每一秒会横向或者纵向移动到相邻的草地上吃草(小易不会走出边界)。 大反派超超想去捕捉可爱的小易,他手里有n个陷阱。第i个陷阱被安置在横坐标为xi ,纵坐标为yi 的位置上,小易一旦走入一个陷阱,将会被超超捕捉。 你为了去解救小易,需要知道小易最少多少秒可能会走入一个陷阱,从而提前解救小易。 输入描述: 第一行为一个整数n(n ≤ 1000),表示超超一共拥有n个陷阱。 第二行有n个整数xi,表示第i个陷阱的横坐标 第三行有n个整数yi,表示第i个陷阱的纵坐标 保证坐标都在草地范围内。 输出描述: 输出一个整数,表示小易最少可能多少秒就落入超超的陷阱 输入例子: 3 4 6 8 1 2 1 输出例子: 3 思路: 计算最短距离 */ public static void main(String[] args) { Scanner in = new Scanner(System.in); while(in.hasNextLine()){ String n = in.nextLine(); String x = in.nextLine(); String y = in.nextLine(); String [] str; int num = 0; ArrayList<Integer> listX = new ArrayList<Integer>(); ArrayList<Integer> listY = new ArrayList<Integer>(); Pattern pattern = Pattern.compile("[ ]"); str = pattern.split(n); num = Integer.parseInt((str[0])); str = pattern.split(x); listX = split(str); str = pattern.split(y); listY = split(str); //int min = listX.get(0) + listY.get(0) - 2; int min = (listX.get(0)-1)*(listX.get(0)-1) + (listY.get(0)-1) * (listY.get(0)-1); int value = 0; int pos = 0, posX, posY; // 寻找最近的陷阱 for(int i = 1; i < num; i++){ value = (listX.get(i)-1)*(listX.get(i)-1) + (listY.get(i)-1) * (listY.get(i)-1); //value = listX.get(i) + listY.get(i) - 2; if(min > value){ min = value; pos = i; } } posX = listX.get(pos); posY = listY.get(pos); System.out.println(posX + ":" + posY); int space = (posY - 1) + (posX - 1); System.out.println(space); } } private static ArrayList<Integer> split(String [] str){ int len = str.length; ArrayList<Integer> list = new ArrayList<Integer>(); for(int i = 0; i < len; i++){ list.add(i, Integer.parseInt(str[i])); } return list; } }
注
曼哈顿与欧几里得距离: 红、蓝与黄线分别表示所有曼哈顿距离都拥有一样长度(12),而绿线表示欧几里得距离有6×√2 ≈ 8.48的长度。
欧几里德(简称欧式)距离适用领域范围:m维空间中两个点之间的真实距离。其计算公式如下:
二维空间的公式
0ρ = sqrt( (x1-x2)^2+(y1-y2)^2 )
三维空间的公式
0ρ = √( (x1-x2)^2+(y1-y2)^2+(z1-z2)^2 )