Islands Travel 微软2016校园招聘笔试题
2016-04-12 16:07
323 查看
单点时限:1000ms
内存限制:256MB
描述
There are N islands on a planet whose coordinates are (X1, Y1),(X2, Y2), (X3,
Y3) ..., (XN, YN).
You starts at the 1st island (X1, Y1)
and your destination is the n-th island (XN, YN).
Travelling between i-th and j-th islands will cost you min{|Xi-Xj|,
|Yi-Yj|} (|a| denotes the absolute
value of a. min{a, b} denotes the smaller value between a and b) gold coins. You want to know what is the minimum cost to travel from the 1st island to the n-th island.
输入
Line 1: an integer N.Line 2~N+1: each line contains two integers Xi and Yi.
For 40% data, N<=1000,0<=Xi,Yi<=100000.
For 100% data, N<=100000,0<=Xi,Yi<=1000000000.
输出
Output the minimum cost.样例输入
3 2 2 1 7 7 6
样例输出
2
题目分析
此题明显是单源最短路径生成算法1. Floyd
一开始看错题了,以为要求能够遍历所有岛的 最短路径,以为是最小生出树算法,写出来TLE,复杂度o(n3);Floyd选择最短边加入节点 生成最小生成树
源代码如下:
<pre name="code" class="java">import java.util.*; public class IslandsTravel1138 { public static void main(String[] args) { Scanner in = new Scanner(System.in); while (in.hasNext()) { int n=in.nextInt(); int[][] a=new int [2]; for(int i=0;i<n;i++) { a[i][0]=in.nextInt(); a[i][1]=in.nextInt(); } int[][] map=new int ; for(int i=0;i<n;i++) { for(int j=i+1;j<n;j++) { map[i][j]=Math.min(Math.abs(a[i][0]-a[j][0]), Math.abs(a[i][1]-a[j][1])); } } List<Integer> list1=new ArrayList<Integer>(); List<Integer> list2=new ArrayList<Integer>(); int min=Integer.MAX_VALUE; int x=0; int y=0; for(int i=0;i<n;i++) { for(int j=i+1;j<n;j++) { if(map[i][j]<min) { min=map[i][j]; x=i; y=j; } } } list1.add(x); list1.add(y); int sum=0; sum+=map[x][y]; for(int i=0;i<n;i++) { if((i!=x)&&(i!=y)) list2.add(i); } while(list1.size()<n) { int[] tmp=new int[2]; int tmpmin=Integer.MAX_VALUE; for(int i=0;i<list1.size();i++) { for(int j=0;j<list2.size();j++) { int xx=list1.get(i); int yy=list2.get(j); if(map[xx][yy]!=0&&map[xx][yy]<tmpmin) { tmpmin=map[xx][yy]; tmp[0]=xx; tmp[1]=yy; } } } sum+=tmpmin; list1.add(tmp[1]); list2.remove(Integer.valueOf(tmp[1])); } System.out.println(sum); } } }
2. dijkstra算法
既然floyd会超时,那就换单源最短路径常见算法dijkstra算法。每次找到一个最短路径,更新其他节点的最短路径。当找到n-1结点的时候结束,复杂度为0(n2);<pre name="code" class="java">import java.util.Scanner; import java.util.*; public class IslandsTravel2 { public static void main(String[] args) { int MAX=Integer.MAX_VALUE; Scanner in = new Scanner(System.in); int n=in.nextInt(); int[][] a=new int [2]; for(int i=0;i<n;i++) { a[i][0]=in.nextInt(); a[i][1]=in.nextInt(); } int[] dis=new int ; boolean[] flag=new boolean ; flag[0]=true; for(int i=1;i<n;i++) { dis[i]=getdis(0,i,a); } for(int i=1;i<n;i++) { int index=-1; int min=MAX; for(int j=1;j<n;j++) { if((!flag[j])&&(dis[j]<min)) { index=j; min=dis[j]; } } if(index==-1) break; flag[index]=true; for(int k=1;k<n;k++) { int disjk=getdis(index,k,a); if(disjk+dis[index]<dis[k]) { dis[k]=disjk+dis[index]; } } } System.out.println(dis[n-1]); } public static int getdis(int i,int j,int[][] a) { return Math.min(Math.abs(a[i][0]-a[j][0]), Math.abs(a[i][1]-a[j][1])); } }
依旧TLE
2. SPFA算法以及优化
后来查资料,了解到SPFA算法,复杂度O(ke)k一般为2这样我们只要找到的边尽可能的少,进行相关优化就可以啦。
我们可以知道我们必须通过离点(x,y)尽可能近的点才能优化此点。
在本题中,最近距离的处理上,还有另一个很重要的性质:
对于任意一个点
i,在x坐标和y坐标排序后,坐标值不等于点
i,且最靠近点
i的点。我们称为点
i的邻居。如下图中所示的绿色点:
通过该图可以知道,邻居节点一定是在虚线的交点处,因此对于点
i,邻居节点至多有4个。并且在图中黄色的区域,也就是点
i的上下左右4个区域内是不存在其他点的。其他点只能存在于绿色的区域内。
假设有一个点
j,存在于绿色区域内,可以证明从点
j直接到点
i的距离一定不会优于点
j先到邻居节点再到点
i。
通过邻居节点则:
由于:
因此有:
所以我们并不需要将点
i和点
j的边进行连接,只需要连接点
i和邻居节点的边即可。
所以最后通过的源代码如下:
<pre name="code" class="java">import java.util.Scanner; import java.util.*; public class IslandsTravel3SPFA { final static int MAXINT = 1000000000; public static void main(String[] args) { int MAX=Integer.MAX_VALUE; Scanner in = new Scanner(System.in); while(in.hasNext()) { int n=in.nextInt(); Node[] node=new Node ; for(int i=0;i<n;i++) { node[i]=new Node(in.nextInt(),in.nextInt(),i); } List<List<Dis>> graph=new ArrayList<List<Dis>>(); for(int i=0;i<n;i++) { graph.add(new ArrayList<Dis>()); } build(node,graph); for(int i=0;i<n;i++) { swap(node[i]); } build(node,graph); int[] dis=new int ; for(int i=1;i<n;i++) { dis[i]=MAX; } LinkedList<Integer> queue=new LinkedList<Integer>(); queue.add(0); //设置queue标志位,避免计算是否包含浪费时间 boolean[] flag=new boolean ; flag[0]=true; while(!queue.isEmpty()) { int k=queue.pollFirst(); List<Dis> list=graph.get(k); flag[k]=false; for(Dis tmp:list) { int num=tmp.num; int d=tmp.d; if(dis[k]+d<dis[num]) { dis[num]=dis[k]+d; if(flag[num]==false) { queue.add(num); flag[num]=true; } } } } System.out.println(dis[n-1]); } in.close(); } public static void build(Node[] A,List<List<Dis>> graph) { Arrays.sort(A); int n=A.length; for(int i=1;i<n;i++) { int num=A[i].num; int pre=A[i-1].num; graph.get(num).add(new Dis(pre,A[i].x-A[i-1].x)); graph.get(pre).add(new Dis(num,A[i].x-A[i-1].x)); } } public static void swap(Node node) { int tmp=node.x; node.x=node.y; node.y=tmp; } public static class Node implements Comparable<Node> { int x; int y; int num; Node(int x,int y,int num) { this.x=x; this.y=y; this.num=num; } @Override public int compareTo(Node node) { // TODO Auto-generated method stub if(this.x>node.x) return 1; else if(this.x<node.x) return -1; else return 0; } } public static class Dis { int num; int d; Dis(int num,int d) { this.num=num; this.d=d; } } }
相关文章推荐
- 微软无线镭射简报鲨8000激光笔记本鼠标 - (2)
- 对《大家都在点赞 Windows Terminal,我决定给你泼一盆冷水》一文的商榷
- 对《大家都在点赞 Windows Terminal,我决定给你泼一盆冷水》一文的商榷
- 微软镜像下载
- 书评:《算法之美( Algorithms to Live By )》
- 微软公布2013年必应搜索十大首页美图
- 动易2006序列号破解算法公布
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- 微软Word 2007数学插件 Microsoft Math 提供下载
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- 巧用微软EWF来保护系统
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解