对于没有学习算法与数据结构的人来说,这个题还是有一定难度的。恰巧,我就是这样的一个人!不过做这道题我还是去翻了一些相关资料的,因为这个问题涉及到了深度优先搜索与广度优先搜索的知识。由于我的学习计划是有这方面的内容的,所以提前看一下也是好的。
首先,这篇博客不是要讲算法,而是要阐述一下自己的做题思路。
完整代码下载链接:https://download.csdn.net/download/ls0111/10493417
---------------------------------我----是----分----割----线-------------------------------------------
题目:(题目是全英文的,有兴趣且有耐心的小伙伴一定可以看得懂,不懂就@我)
- The distance of the route A-B-C.
- The distance of the route A-D.
- The distance of the route A-D-C.
- The distance of the route A-E-B-C-D.
- The distance of the route A-E-D.
- 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).
- 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).
- The length of the shortest route (in terms of distance to travel) from A to C.
- The length of the shortest route (in terms of distance to travel) from B to B.
- 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.
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.总结
本来以为,会长篇大论的去讲递归算法什么的,发现写完之后也就那么几行而已。还是来写总结吧!其实这道题关键信息在与算法与数据结构,如果我以前学过这个知识,肯定就知道如何下手。另外,我这里是计算出所有结果之后,然后进行筛选找出答案的。现在这个数据量很小,这个方法可以解决这个问题。但是数据量增多的话,性能肯定会成为一大瓶颈。如果数据量很大的话,还是建议把问题细分之后,采用不同的方式去寻找结果。这样会排除一些冗余数据,会提高不少效率。
最后,现在还没有学习到算法与数据结构,也许很多东西自己理解不对,或者与正确表述有所偏差,还请各位前辈多多赐教!非常感谢。