Islands Travel 微软2016校园招聘笔试题

时间限制: 10000ms
单点时限: 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[n][2];
			for(int i=0;i<n;i++)
			{
				a[i][0]=in.nextInt();
				a[i][1]=in.nextInt();
			}
			int[][] map=new int[n][n];
			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[n][2];
			for(int i=0;i<n;i++)
			{
				a[i][0]=in.nextInt();
				a[i][1]=in.nextInt();
			}
			int[] dis=new int[n];
			boolean[] flag=new boolean[n];
			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的邻居。如下图中所示的绿色点:

pic1

通过该图可以知道,邻居节点一定是在虚线的交点处,因此对于点i,邻居节点至多有4个。并且在图中黄色的区域,也就是点i的上下左右4个区域内是不存在其他点的。其他点只能存在于绿色的区域内。

假设有一个点j,存在于绿色区域内,可以证明从点j直接到点i的距离一定不会优于点j先到邻居节点再到点i

formula1

通过邻居节点则:

formula2

由于:

formula3

因此有:

formula4

所以我们并不需要将点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[n];
			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[n];
			for(int i=1;i<n;i++)
			{
				dis[i]=MAX;
			}
			LinkedList<Integer> queue=new LinkedList<Integer>();
			queue.add(0);
			//设置queue标志位,避免计算是否包含浪费时间
		   boolean[] flag=new boolean[n];
		   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;
    	}
    }
    
    

}


 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值