Problem one: Trains

    对于没有学习算法与数据结构的人来说,这个题还是有一定难度的。恰巧,我就是这样的一个人!不过做这道题我还是去翻了一些相关资料的,因为这个问题涉及到了深度优先搜索与广度优先搜索的知识。由于我的学习计划是有这方面的内容的,所以提前看一下也是好的。

    首先,这篇博客不是要讲算法,而是要阐述一下自己的做题思路。

    完整代码下载链接:https://download.csdn.net/download/ls0111/10493417

---------------------------------我----是----分----割----线-------------------------------------------

题目:(题目是全英文的,有兴趣且有耐心的小伙伴一定可以看得懂,不懂就@我)

Problem one: Trains
 
The local commuter railroad services a number of towns in Kiwiland.  Because of monetary concerns, all of the tracks are 'one-way.'  That is, a route from Kaitaia to Invercargill does not imply the existence of a route from Invercargill to Kaitaia.  In fact, even if both of these routes do happen to exist, they are distinct and are not necessarily the same distance!
 
The purpose of this problem is to help the railroad provide its customers with information about the routes.  In particular, you will compute the distance along a certain route, the number of different routes between two towns, and the shortest route between two towns.
 
Input:  A directed graph where a node represents a town and an edge represents a route between two towns.  The weighting of the edge represents the distance between the two towns.  A given route will never appear more than once, and for a given route, the starting and ending town will not be the same town.
 
Output: For test input 1 through 5, if no such route exists, output 'NO SUCH ROUTE'.  Otherwise, follow the route as given; do not make any extra stops!  For example, the first problem means to start at city A, then travel directly to city B (a distance of 5), then directly to city C (a distance of 4).
  1. The distance of the route A-B-C.
  2. The distance of the route A-D.
  3. The distance of the route A-D-C.
  4. The distance of the route A-E-B-C-D.
  5. The distance of the route A-E-D.
  6. The number of trips starting at C and ending at C with a maximum of 3 stops.  In the sample data below, there are two such trips: C-D-C (2 stops). and C-E-B-C (3 stops).
  7. The number of trips starting at A and ending at C with exactly 4 stops.  In the sample data below, there are three such trips: A to C (via B,C,D); A to C (via D,C,D); and A to C (via D,E,B).
  8. The length of the shortest route (in terms of distance to travel) from A to C.
  9. The length of the shortest route (in terms of distance to travel) from B to B.
  10. The number of different routes from C to C with a distance of less than 30.  In the sample data, the trips are: CDC, CEBC, CEBCDC, CDCEBC, CDEBC, CEBCEBC, CEBCEBCEBC.
 
Test Input:
For the test input, the towns are named using the first few letters of the alphabet from A to D.  A route between two towns (A to B) with a distance of 5 is represented as AB5.
Graph: AB5, BC4, CD8, DC8, DE6, AD5, CE2, EB3, AE7
Expected Output:
Output #1: 9
Output #2: 5
Output #3: 13
Output #4: 22
Output #5: NO SUCH ROUTE
Output #6: 2
Output #7: 3
Output #8: 9
Output #9: 9

Output #10: 7

最终我们提取到的有用信息大概是这些:

1.已知:

有五个节点(顶点,或者说五个城市都可以)ABCDE,若干城市直接可以连通,但是这个路线是有方向的。Graph: AB5, BC4, CD8, DC8, DE6, AD5, CE2, EB3, AE7,其中AB5代表存在路线A-B,路线长度(或者说权值)为5,其他类似。

2.求解:

一共有10道题:

    1~5题很容易,并且也属于同一类问题。即,给出既定路线,求路线长度。

    6~10题看到很多人把它细分了好几种类型,我个人认为其实也是一类问题。即,给出起始地点与目的地,求相关数据问题。最多加上限定条件(最多经过几站路【stops】、路线长度小于一定值或者一定要经过几站到达)。

所以,我最终只写了两个方法。

本题目录结构:

1.类结构介绍:

首先,我是把路线图规划为一个GraphMap的类,该类主要提供地图数据录入,计算两点距离或路线的方法。

Route类就是有起点与终点的一条路线,并可以获取到该路线经历了多少站,与该路线的距离。

Trip类是由Route聚合而成,因为一个旅行从西安到北京会有很多可选线路。该类应提供获取最短路线的方法与所有路线数量的方法等。

Trains类没有细分,在这里我是把他作为一种交通工具,并且他有一个地图,可以告诉他你要从哪到哪,然后他给你制定一个旅行计划Trip,其实这样看起来它的只能主要是为你规划路线为你服务的。可能叫他旅行社更好一些吧。

以上代码比较简单,不再粘贴。有意见可以@我。- -!

接下来介绍核心类:

package cn.lys.thoughtwork;

import java.util.ArrayList;
import java.util.List;

public class GraphMap {
	private static final char START_NODE = 'A';
	public static final String NO_SUCH_ROUTE = "NO SUCH ROUTE";
	public static final int OPTIMAL_ALGORITHM = -1;
	public static final int UNLIMITED_STOPS = Integer.MAX_VALUE;
	public static final int UNLIMITED_DISTANCE = -1;
	private static List<Route> routes;
	
	/** 
	 * Map of ABCDE places. 
	 * Graph: AB5, BC4, CD8, DC8, DE6, AD5, CE2, EB3, AE7 .
	 **/
	private int[][] map = {
			      /** A  B  C  D  E **/
			/** A **/{0, 5, 0, 5, 7},
			/** B **/{0, 0, 4, 0, 0},
			/** C **/{0, 0, 0, 8, 2},
			/** D **/{0, 0, 8, 0, 6},
			/** E **/{0, 3, 0, 0, 0}
	};
	
	public static void main(String[] args) {
		GraphMap gm = new GraphMap();
		char start = 'B';
		char end = 'B';
		int stops = -4;
		int maxDistance = -1;
		gm.makeTripFromStart2End(start, end, stops, maxDistance);
	}
	
	/**
	 * Get the distance of the route which you input.
	 * @param start: Position of starting.
	 * @param end: Position of ending.
	 * @return The distance between 'start' and 'end'.
	 */
	public int getDistance(char start, char end){
		return getLengthByIndex(start - START_NODE, end - START_NODE);
	}

	/**
	 * Find all routes from 'start' to 'end'.
	 * @param start: The starting of route.
	 * @param end: The ending of route.
	 * @param stops: The max stops in this route.
	 * @param maxDistance: The max distance in this route.
	 * @return The trip contains all routes from 'start' to 'end'.
	 */
	public Trip makeTripFromStart2End(char start, char end, int stops, int maxDistance){
		if (!checkPosition(start - START_NODE, end - START_NODE)) {
			return null;
		}
		// init routes param
		routes = new ArrayList<Route>();
		// find all routes
		search(start - START_NODE, end - START_NODE, "" + start, 0, stops, maxDistance);
		// construct a trip that contains all routes
		Trip trip = new Trip(routes, start, end);
		return trip;
	}
	
	/**
	 * find all routes that meet the requirements. 
	 * @param x
	 * @param y
	 */
	private void search(int x, int y, String path, int distance, int stops, int maxDistance){
		for(int i=0;i<map[x].length;i++){
			// 1.exist a route;
			// 2.stops < requirement stops;
			// 3.eliminate the starting;
			// 4.don't walk repeated station.
			// 5.distance < maxDistance
			if(map[x][i] > 0 && (stops > 0 ? (path.length() < stops + 1) : (!path.substring(1).contains(String.valueOf((char)(i + START_NODE))))) 
					&& (maxDistance > 0 ? (distance < maxDistance - map[x][i]) : true)){
				// arrive the ending
				if(i == y){
					routes.add(new Route(path + (char)(y + START_NODE), distance + map[x][i]));
					System.out.println("path=" + path + (char)(y + START_NODE) + ", distance=" + (distance + map[x][i]));
				}
				search(i, y, path + (char)(i + START_NODE), distance + map[x][i], stops, maxDistance);
			}
		}
	}
	
	/**
	 * Get the distance by index in this map.
	 * @param x: X-axis in this map.
	 * @param y: Y-axis in this map.
	 * @return 0 represents illegal params or there doesn't exist the route between x and y.
	 */
	private int getLengthByIndex(int x, int y){
		if (!checkPosition(x, y)) {
			return 0;
		}
		return map[x][y];
	}
	
	/**
	 * x,y params must be legal in this situation
	 * @param x
	 * @param y
	 * @return
	 */
	private boolean checkPosition(int x, int y){
		if (x < 0 || y < 0 || x > map.length || y >= map.length) {
			return false;
		}
		return true;
	}
	
	public int[][] getMap() {
		return map;
	}
	public void setMap(int[][] map) {
		this.map = map;
	}
}

其中,makeTripFromStart2End(char start, char end, int stops, int maxDistance)方法是计算从start到end这两点的所有路线。且需要满足要求:一个是不能超过stops站数量,另一个是最长距离不能超过maxDistance。如果不限制站数量或距离,则可以使用UNLIMITED_STOPS或UNLIMITED_DISTANCE常量进行传参。

该方法也是整个问题的核心算法(计算距离的算法很简单,相信大家都能看懂),整个算法是急于一个二维数组展开的,就是该类中定义的map属性。如下表格,两个点相交的位置就是他们之间的路线,存在则记为路线长度,不存在则记为0。其余以此类推(我懒我骄傲)。

起点\终点 A B C D E
A A-A:不存在,记为0 A-B:存在,记其路线长度5      
B          
C          
D          
E          

2.算法解释:

        首先我们会得到一个起始点,假如为A,就获取到第一行记录。然后遍历获取A可以到达的地点,这里会先找到B点。然后判断该地点是否满足要求(这个要求需要根据所传参数来定义:即,这个地点是否是终点;是否满足不超过最大距离的条件;是否满足不超过最大站数的条件等),若满足,就创建一条路线(Route)存入到routes变量中。不满足的话,就递归调用该方法。此时,起点可以认为是B地点,然后所经过的站数加1,距离加A-B的距离。以此往复调用,直到找到所有满足条件的结果。最后,这些所找到的路线都已经存放到了routes变量中。返回一个旅行计划Trip结果。

3.测试:

我是使用的Junit做的测试,把题目中的10道题给加进去了,最后测试都通过了。但是我想说这不是最优解。恩,一定不是。

package cn.lys.thoughtwork.test;

import static org.junit.Assert.*;
import org.junit.Test;

import cn.lys.thoughtwork.GraphMap;
import cn.lys.thoughtwork.Trains;
import cn.lys.thoughtwork.Trip;

public class TrainsTest {
	private Trains train = new Trains();

	// 1.The distance of the route A-B-C.
	@Test
	public void test1() {
		String route = "A-B-C";
		assertEquals("9", train.calcDistance(route));
	}
	
	// 2.The distance of the route A-D.
	@Test
	public void test2() {
		String route = "A-D";
		assertEquals("5", train.calcDistance(route));
	}
	
	// 3.The distance of the route A-D-C.
	@Test
	public void test3() {
		String route = "A-D-C";
		assertEquals("13", train.calcDistance(route));
	}
	
	// 4.The distance of the route A-E-B-C-D.
	@Test
	public void test4() {
		String route = "A-E-B-C-D";
		assertEquals("22", train.calcDistance(route));
	}
	
	// 5.The distance of the route A-E-D.
	@Test
	public void test5() {
		String route = "A-E-D";
		assertEquals(GraphMap.NO_SUCH_ROUTE, train.calcDistance(route));
	}
	
	// 6.The number of trips starting at C and ending at C with a maximum of 3 stops. In the sample data below, there are two such trips: C-D-C (2 stops). and C-E-B-C (3 stops).
	@Test
	public void test6() {
		Trip trip = train.calcAllKindsOfTrips('C', 'C', 3, GraphMap.UNLIMITED_DISTANCE);
		assertEquals(2, trip.getNumOfRouteInThisTrip());
	}
	
	// 7.The number of trips starting at A and ending at C with exactly 4 stops. In the sample data below, there are three such trips: A to C (via B,C,D); A to C (via D,C,D); and A to C (via D,E,B).
	@Test
	public void test7() {
		int stops = 4;
		Trip trip = train.calcAllKindsOfTrips('A', 'C', stops, GraphMap.UNLIMITED_DISTANCE);
		assertEquals(3, trip.getNumOfRouteExactlyStops(stops));
	}
	
	// 8.The length of the shortest route (in terms of distance to travel) from A to C.
	@Test
	public void test8() {
		Trip trip = train.calcAllKindsOfTrips('A', 'C', GraphMap.OPTIMAL_ALGORITHM, GraphMap.UNLIMITED_DISTANCE);
		assertEquals(9, trip.getShotestRouteDistance());
	}
	
	// 9.The length of the shortest route (in terms of distance to travel) from B to B.
	@Test
	public void test9() {
		Trip trip = train.calcAllKindsOfTrips('B', 'B', GraphMap.OPTIMAL_ALGORITHM, GraphMap.UNLIMITED_DISTANCE);
		assertEquals(9, trip.getShotestRouteDistance());
	}
	
	// 10.The number of different routes from C to C with a distance of less than 30. In the sample data, the trips are: CDC, CEBC, CEBCDC, CDCEBC, CDEBC, CEBCEBC, CEBCEBCEBC.
	@Test
	public void test10() {
		int maxDistance = 30;
		Trip trip = train.calcAllKindsOfTrips('C', 'C', 9, maxDistance);
		assertEquals(7, trip.getNumOfRouteInThisTrip());
	}
}

3.总结

本来以为,会长篇大论的去讲递归算法什么的,发现写完之后也就那么几行而已。还是来写总结吧!其实这道题关键信息在与算法与数据结构,如果我以前学过这个知识,肯定就知道如何下手。另外,我这里是计算出所有结果之后,然后进行筛选找出答案的。现在这个数据量很小,这个方法可以解决这个问题。但是数据量增多的话,性能肯定会成为一大瓶颈。如果数据量很大的话,还是建议把问题细分之后,采用不同的方式去寻找结果。这样会排除一些冗余数据,会提高不少效率。

最后,现在还没有学习到算法与数据结构,也许很多东西自己理解不对,或者与正确表述有所偏差,还请各位前辈多多赐教!非常感谢。

猜你喜欢

转载自blog.csdn.net/ls0111/article/details/80775411
one