地铁线路图中任意两点间所有路径高效算法

在求图线任意两点间最短路径时,利用floyd、dijdstra等成熟的算法可以求得,效率还不错。但要求换乘最少、最舒适等路径时,需要求线网图中任意两个点的所有路径,然后根据条件筛选,以上算法无能为力。本人最近做个小项目需要用到这个需求,因此在网上搜索相关资料,找到一个利用栈采用深度优先搜索的算法,利用此算法在下图11条线路190余个站中测试,任意两点间所有路径平均耗时15秒,不能满足需求。

于是,自己琢磨着写了一个算法,现将其记录如下:

第一步:将每条线路视为一个结点,生成所有乘坐线路顺序列表。如上图中楚河汉街——中山公园的路径中,首先采用广度优先搜索生成[[4,2],[4,8,1,2],[4,3,2],......],这样的路径,在生成中剔除明显不合理的路径,如[4,2,7,1,2]这样的路径。

第二步:求第一步生成的线路顺序中相邻两条线的交点(即换乘站),生成以换乘站作为节点的顺序路径。如第一步中[4,3,2]这条线路顺序,4和3的交点为王家湾,3和2的交点为范湖和宏图大道,因此可生成[楚河汉街,王家湾,范湖,中山公园]以及[楚河汉街,王家湾,宏图大道,中山公园]这两起点、终点以及换乘站构成的路径。

第三步:将第二步中每条路径相邻两个站点之间其他站点补齐,即是从起点至终点的完整路径。

因为在第一步剔除了许多不合理路径,因此最后生成所有路径中比以站点深度优先搜索得出来的所有路径少得多,前者为1000余条,后者为15万条。不过没关系,剔除的路径对我们来说没有任何意义。

算法中适用存在环线的线网图,将Line对象中的isCircle设置为true即可。

由于篇幅原因,以下只贴算法中的关键代码,完整的项目以点击下载图中任意两点间所有路径高效算法

 

首先介绍下算法中存储路径的数据结构:树

Tree:

public class SolutionTree {
	
	private TreeNode root;//权的根节点
	
	public SolutionTree(int Id)
	{
		root = new TreeNode(Id);
	}

	public TreeNode getRoot() {
		return root;
	}

	public void setRoot(TreeNode root) {
		this.root = root;
	}
	
}

TreeNode:

public class TreeNode implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 656317088559367582L;
	private int Id;  //权节点id
    protected TreeNode parentNode;//父节点
    protected List<TreeNode> childList;//子节点列表
 
    public TreeNode(int Id) {
    	this.Id=Id;
        initChildList();
    }
 
    public TreeNode(int Id,TreeNode parentNode) {
    	this.Id=Id;
        this.parentNode=parentNode;
        initChildList();
    }


   //此处省略get、set以及一些内部方法
 
 
 
}

然后是存储站点信息以及线路信息的Class:

Station.class:

public class Station {

	private int id;//车站id
	private String name;//车站名
	private Station nextSta;//下个站
	private Station prevSta;//上个站
	private int line;//车站所在的线路
	private List<Integer> transferLines = new ArrayList<Integer>();//当前站可换乘线路列表,不是换乘,列表中只有一个0元素
	
    //此外省略了get、set以及一些内部方法

}

Line.class:

public class Line {

	private int id; //线路id
	private List<Station> stationList = new ArrayList<Station>();//本条线的车站列表
	private boolean isCircle ;//是否为环线

     //此外省略了get、set以及一些内部方法

}

最后就是算法了,算法中需要三个初始数据,graph:站点列表,将每个站点对象中的所有属性按实际情况赋值;matrix:费用矩阵,可连通,设置为连通的费用值,不可连通,设置为无穷大,算法中统一相邻站点费用为2,换乘站连接费用为5,实际使用中可读取费用数据后赋值;lineTable:线路列表,线路id作为key值。以上三个初始数据在实际使用中可通过第二个构造函数传入赋值。代码如下:

public class PathSearch {  

	private List<Station> graph;  //车站列表,
	private static final int INF=Integer.MAX_VALUE;
	private int[][] matrix;//费用矩阵
	private Map<Integer,Line> lineTable = new HashMap<Integer,Line>();//线路表
	
	/**
	 * 从数据库或文件读取站点数据,费用表等数据,初始化数据
	 */
	public PathSearch()
	{
		try
		{
			//要求根据库中的车站按所在线中的顺序依次存储
			String sql = "Select * From tab_station order by id";
			List<Map<String,Object>> result = MyDatabase.search(sql);
			graph = new ArrayList<Station>();
			List<Station> temp  = new ArrayList<Station>();
			int line = Integer.parseInt(result.get(0).get("line").toString());
			for(int i=0;i<result.size();i++) 
			{
				Map<String,Object> data = result.get(i);
				Station sta = new Station();
				sta.setId(i);
				sta.setLine(Integer.parseInt(data.get("line").toString()));
				sta.setName(data.get("name").toString());
				if(!(line == sta.getLine()) || i==result.size()-1)
				{
					Line tl = new Line();
					tl.setId(line);
					tl.setStationList(temp);
					//若线路为环线,在此设置   tl.setCircle(true);
					lineTable.put(line, tl);
					line = sta.getLine();
					if(i==result.size()-1)
					{
						temp.add(sta);
					}
					temp  = new ArrayList<Station>();
					
				}
				temp.add(sta);
				List<String> list = Arrays.asList(data.get("transer").toString().replace(" ", "").split(","));
				for(String tl : list)
				{
					sta.addTransferLine(Integer.parseInt(tl));
				}
				
				graph.add(sta);
			}
			
			//将前后车站相连,graph中的元素也随着改变
			for(int key : lineTable.keySet())
			{
				Line tl = lineTable.get(key);
				int lineLength = tl.getStationList().size();
				if(tl.isCircle())//如果是环线,首尾相连
				{
					tl.getStationList().get(0).setPrevSta(tl.getStationList().get(lineLength-1));
					tl.getStationList().get(lineLength-1).setNextSta(tl.getStationList().get(0));
					
				}
				tl.getStationList().get(0).setNextSta(tl.getStationList().get(1));
				tl.getStationList().get(lineLength-1).setPrevSta(tl.getStationList().get(lineLength-2));
				
				for(int i=1;i<lineLength-1;i++)
				{
					tl.getStationList().get(i).setPrevSta(tl.getStationList().get(i-1));
					tl.getStationList().get(i).setNextSta(tl.getStationList().get(i+1));
				}
			}
			
			matrix = new int[graph.size()][graph.size()];
			//权重数组
			for(int i = 0; i<graph.size();i++)
			{
				Station stai = graph.get(i);
				
				for(int j = 0;j<graph.size();j++)
				{
					Station staj = graph.get(j);
					if(i==j)
					{
						matrix[i][j] = 0;
					}
					//票价计算,换乘站间设置权重为0,若为时间权限,可在此设置换乘权重
					else if(stai.getName().equals(staj.getName()))
					{
						matrix[i][j] = 5;
					}
					else
					{
						matrix[i][j] = INF;
					}
					//相邻车站权重统一设置为2
					if(stai.getNextSta()!=null)
					{
						if(stai.getNextSta().getId() == staj.getId())
						{
							matrix[i][j] = 2;
						}
					}
					if(stai.getPrevSta()!=null)
					{
						if(stai.getPrevSta().getId() == staj.getId())
						{
							matrix[i][j] = 2;
						}
					}
					if(staj.getNextSta()!=null)
					{
						if(staj.getNextSta().getId() == stai.getId())
						{
							matrix[i][j] = 2;
						}
					}
					if(staj.getPrevSta()!=null)
					{
						if(staj.getPrevSta().getId() == stai.getId())
						{
							matrix[i][j] = 2;
						}
					}
				}
			}
			
			
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		
	}
	
	/**
	 * 从外部将站点列表,费用矩阵及线路表传入,初始化数据
	 */
	public PathSearch(List<Station> graph,int[][] matrix,Map<Integer,Line> lineTable)
	{
		this.graph = graph;
		this.matrix = matrix;
		this.lineTable = lineTable;
	}

	
	//记录每对起始id第一次调用getAllPath方法得到数据,若相同的起始id再次再次调用时,可直接调用XXNoMakeAllPath()方法
	private List<List<Integer>> allPath;
	
	/**
	 * 生成起点到终点的所有路径,该方法返回的所有路径比实际的所有路径要少得多,因为在方法中去除了一些明显不合理的路径,
	 * 例如2号线转3号线,再从3号线转2号线的路径明显不合理
	 * @param startStaId 起点id
	 * @param endStaId  终点id
	 * @return  径路列表
	 */
	private List<List<Integer>> getAllPath(int startStaId, int endStaId)
	{
		Station startSta = graph.get(startStaId);
		Station endSta = graph.get(endStaId);
		
		//以起始线路id作为根节点初始化一棵树
		SolutionTree tree = new SolutionTree(startSta.getLine());
		makeTreeNode(tree.getRoot(),endSta.getLine());
		
		//获取树的所有叶子节点
		
		List<TreeNode> ziYeList = new ArrayList<TreeNode>(); 
		tree.getRoot().getZiYe(ziYeList);
		
		
		Iterator<TreeNode> tempList = ziYeList.iterator();
		//删除id不是终点站的叶子结点
		while(tempList.hasNext())
		{
			TreeNode node = tempList.next();
			if(node.getId()!=endSta.getLine())
			{
				tempList.remove();
			}
		}
		
		//每个叶子节点的父辈节点反转后再加上节点本身,即为从起点到终点经过线路顺序
		List<List<Integer>> tempResult = new ArrayList<List<Integer>>();
		for(TreeNode node : ziYeList)
		{
			List<Integer> list = node.getEldersID();
			Collections.reverse(list);
			list.add(node.getId());
			tempResult.add(list);
		}
		
		
		//通过每条线路顺序,获取换乘站的顺序路径
		List<List<Integer>> staTempResult = new ArrayList<List<Integer>>();
		for(List<Integer> temp : tempResult)
		{
			
			//以起点站id作根要点id初始化树
			SolutionTree staTree = new SolutionTree(startStaId);
			
			for(int i = 0; i < temp.size()-1; i++)
			{
				List<TreeNode> fatherList = new ArrayList<TreeNode>();
				staTree.getRoot().getZiYe(fatherList);
				Line line = lineTable.get(temp.get(i));
				Line nextLine = lineTable.get(temp.get(i+1));
				//两条线的交点即为换乘站,
				List<Integer> jiaoDianList = getJiaoDianZhan(line,nextLine.getId());
				
				//为每个叶子节点增加子节点
				for(TreeNode father : fatherList)
				{
					
					for(int staId : jiaoDianList)
					{
						//如果交点站为起始车站,则将换乘站所有下条线路的id作为一个节点添加到父节点中
						if(staId == startStaId)
						{
							Station nextSta = nextLine.getStation(line.getStation(staId).getName());
							TreeNode node2 = new TreeNode(nextSta.getId(), father);
							father.addChildNode(node2);
						}
						//否则,则换乘站所有当前线路的id作为一个节点添加到父节点中,同时将换乘站所有下条线路的id作为一个节点添加到刚添加的节点中
						else
						{
							TreeNode node1 = new TreeNode(staId, father);
							father.addChildNode(node1);
							Station nextSta = nextLine.getStation(line.getStation(staId).getName());
							TreeNode node2 = new TreeNode(nextSta.getId(), node1);
							node1.addChildNode(node2);
						}
						
					}
				}
				
			}
			List<TreeNode> fatherList = new ArrayList<TreeNode>();
			staTree.getRoot().getZiYe(fatherList);
			//将所有叶子节点的父辈节点反转并添加该叶子节点id即为第i条线路顺序所经过的换乘站顺序id
			for(TreeNode node : fatherList)
			{
				List<Integer> list = node.getEldersID();
				Collections.reverse(list);
				list.add(node.getId());
				if(!list.contains(endStaId))
				{
					list.add(endStaId);
				}
				staTempResult.add(list);
				//System.out.println(list);
			}
		}
		
		
		List<List<Integer>> result = new ArrayList<List<Integer>>();
		for(List<Integer> temp : staTempResult)
		{
			List<Integer> path = new ArrayList<Integer>();
			
			for(int i=0;i<temp.size()-1;i++)
			{
				Station sta = graph.get(temp.get(i));
				Station nextSta = graph.get(temp.get(i+1));
				//两站之间在同一条线,将两站之间的站点补全
				if(sta.getLine()==nextSta.getLine())
				{
					List<List<Integer>> tempPath = lineTable.get(sta.getLine()).getPathInLine(sta.getId(), nextSta.getId());
					if(tempPath.size()==1)
					{
						path.addAll(tempPath.get(0));
					}
					else
					{
						int minIndex = -1;
						int minDistance = Integer.MAX_VALUE;
						for(int index=0;index<tempPath.size();index++)
						{
							int distance = getDistance(tempPath.get(index));
							if(minDistance > distance)
							{
								minIndex = index;
								minDistance = distance;
							}
						}
						if(minIndex!=-1)
						{
							path.addAll(tempPath.get(minIndex));
						}
					}
					
				}
				else if(i==temp.size()-2)
				{
					path.add(nextSta.getId());
				}
			}
			result.add(path);
		}
		allPath = result;
		
		return result;
	}

	/**
	 * 获取两条线路的交点
	 * @param line 当前线路id
	 * @param nextLineId  下条线路id
	 * @return  返回两条线路交点集合列表
	 */

	private List<Integer> getJiaoDianZhan(Line line, int nextLineId) {
		// TODO Auto-generated method stub
		List<Integer> result = new ArrayList<Integer>();
		//为同一条,返回空列表
		if(line.getId() == nextLineId)return result;
		
		for(Station sta : line.getStationList())
		{
			//当前线路的车站的换乘列表中包含下条线路,表明有交集
			if(sta.getTransferLines().contains(nextLineId))
			{
				result.add(sta.getId());
			}
		}
		return result;
	}

	/**
	 * 为当前树节点添加子节点
	 * @param father 当前节点
	 * @param endLine 终点所在的线路id,用于判断递归结束条件
	 */

	private void makeTreeNode(TreeNode father,int endLine) {
		// TODO Auto-generated method stub
		List<Integer> transferList = getXiangGuanXianLu(father,endLine);
		for(int line : transferList)
		{
			TreeNode node = new TreeNode(line,father);
			father.addChildNode(node);
			//递归直至当前线路等于终点站所在的线路
			if(line!=endLine)
			{
				makeTreeNode(node, endLine);
			}
		}
	}


	/**
	 * 获取与当前线路有交集的线路id
	 * @param father 当前线路的树节点
	 * @param endLine 终点所在的线路id
	 * @return 返回与当前线路有交集的线路id列表
	 */
	private List<Integer> getXiangGuanXianLu(TreeNode father,int endLine) {
		// TODO Auto-generated method stub
		List<Integer> result = new ArrayList<Integer>();
		Line line = lineTable.get(father.getId());
		
		//获取当前节点的父辈节点id列表
		List<Integer> temp = father.getEldersID();
		for(Station sta : line.getStationList())
		{
			for(int tl : sta.getTransferLines())
			{
				//如果是换乘站,列表中不存在当前相关的线路id,
				//除当前相关的线路id为终点点所在的线路id外,当前节点的父辈节点中不能包含此id,同时此id不能与当前节点的id相同
				//满足以上条件,才能作为当前节点的子节点
				if(tl!=0 && !result.contains(tl) && (tl == endLine || 
						(!temp.contains(tl) && tl != father.getId())))
				{
					result.add(tl);
				}
			}
		}
		return result;
	}


	/**
	 * 根据费用矩阵,获取路径的费用总和
	 * @param path 路径列表
	 * @return 返回路径的费用总和
	 */
	private int getDistance(List<Integer> path)
	{
		int sum = 0;
		for(int i=0;i<path.size()-1;i++)
		{
			sum += matrix[path.get(i)][path.get(i+1)];
		}
		
		return sum;
		
	}
	
	
	/**
	 * 获取费用最小的路径
	 * @param allPath 所有路径列表
	 * @return  返回费用最小的路径
	 */
	private  List<List<Integer>> makeShortPath(List<List<Integer>> allPath)
	{
		if(allPath.size()==0)return allPath;
		List<Integer> distance = new ArrayList<Integer>();
		for(List<Integer> path : allPath)
		{
			distance.add(getDistance(path));
		}
		float minDistance = Collections.min(distance);
		List<List<Integer>> result = new ArrayList<List<Integer>>();
		for(int i=0;i<allPath.size();i++)
		{
			if(distance.get(i) == minDistance)
			{
				result.add(allPath.get(i));
			}
		}
		return result;
	}
	
	
	/**
	 * 获取换乘最少的路径
	 * @param allPath 所有路径列表
	 * @return  返回换乘最少的路径
	 */
	private  List<List<Integer>> makeTransferLessPath(List<List<Integer>> allPath)
	{
		if(allPath.size()==0)return allPath;
		List<Integer> transferNumList = new ArrayList<Integer>();
		for(List<Integer> path : allPath)
		{
			int sum = 0;
			for(int i=0;i<path.size()-1;i++)
			{
				//路径中第i个站与第i+1个站不是同一条线,表明换乘,终点站为换乘站时,不计换乘个数
				if(graph.get(path.get(i)).getLine() != graph.get(path.get(i+1)).getLine() && i!=path.size()-2)
				{
					sum ++;
				}
			}
			transferNumList.add(sum);
		}
		float minTransferNum = Collections.min(transferNumList);
		List<List<Integer>> result = new ArrayList<List<Integer>>();
		for(int i=0;i<allPath.size();i++)
		{
			if(transferNumList.get(i) == minTransferNum)
			{
				result.add(allPath.get(i));
			}
		}
		return result;
	}

	/**
	 * 获取费用最小的路径,并将id转化成站名
	 * @param startStaId 起始id
	 * @param endStaId 终点id
	 * @return  返回费用最小的字符串路径
	 */
	public List<List<String>> getShortPath(int startStaId, int endStaId) {

		List<List<Integer>> allPath = getAllPath(startStaId, endStaId);
		
		List<List<String>> result = new ArrayList<List<String>>();
		//获取路径最短的路径
		 List<List<Integer>> temp = makeShortPath(allPath);
		 
		 //如果有两条及以上的最短路径,获取换乘最少的路径
		 if(temp.size()>1)
		 {
			 temp = makeTransferLessPath(temp);
		 }
		for(int i=0;i<temp.size();i++)
		{
			result.add(transformPath(temp.get(i)));
		}
		
		return result;
	}
	
	/**
	 * 获取费用最小的路径,并将id转化成站名,不需要生成AllPath
	 * @param startStaId 起始id
	 * @param endStaId 终点id
	 * @return  返回费用最小的字符串路径
	 */
	public List<List<String>> getShortPathNoMakeAllPath(int startStaId, int endStaId) {

		
		List<List<String>> result = new ArrayList<List<String>>();
		
		if(allPath==null)return result;
		//获取路径最短的路径
		 List<List<Integer>> temp = makeShortPath(allPath);
		 
		 //如果有两条及以上的最短路径,获取换乘最少的路径
		 if(temp.size()>1)
		 {
			 temp = makeTransferLessPath(temp);
		 }
		for(int i=0;i<temp.size();i++)
		{
			result.add(transformPath(temp.get(i)));
		}
		
		return result;
	}
	
	/**
	 * 获取换乘最少的路径,并将id转化成站名,不需要生成AllPath
	 * @param startStaId 起始id
	 * @param endStaId 终点id
	 * @return  返回换乘最少的字符串路径
	 */
	public List<List<String>> getTransferLessPathNoMakeAllPath(int startStaId, int endStaId) {
		// TODO Auto-generated method stub
		//List<List<Integer>> allPath = getAllPath(startStaId, endStaId);
		List<List<String>> result = new ArrayList<List<String>>();
		if(allPath==null)return result;
		//获取换乘个数最少的路径
		List<List<Integer>> temp = makeTransferLessPath(allPath);
		//如果有多条换乘个数一样的路径,获取其中路径最短的
		if(temp.size()>1)
		{
			temp = makeShortPath(temp);
		}
		for(int i=0;i<temp.size();i++)
		{
			result.add(transformPath(temp.get(i)));
		}
		
		return result;
	}

	/**
	 * 获取换乘最少的路径,并将id转化成站名
	 * @param startStaId 起始id
	 * @param endStaId 终点id
	 * @return  返回换乘最少的字符串路径
	 */
	public List<List<String>> getTransferLessPath(int startStaId, int endStaId) {
		// TODO Auto-generated method stub
		List<List<Integer>> allPath = getAllPath(startStaId, endStaId);
		List<List<String>> result = new ArrayList<List<String>>();
		//获取换乘个数最少的路径
		List<List<Integer>> temp = makeTransferLessPath(allPath);
		//如果有多条换乘个数一样的路径,获取其中路径最短的
		if(temp.size()>1)
		{
			temp = makeShortPath(temp);
		}
		for(int i=0;i<temp.size();i++)
		{
			result.add(transformPath(temp.get(i)));
		}
		
		return result;
	}

	/**
	 * 将id路径转化成站名的路径
	 * @param path
	 * @return
	 */
	private List<String> transformPath(List<Integer> path)
	{
		List<String> result = new ArrayList<String>();
		//获取起点站线路
		String startLine = getStartLine(path);
		for(int i=0;i<path.size()-1;i++)
		{
			Station sta1 = graph.get(path.get(i));
			Station sta2 = graph.get(path.get(i+1));
			Station temp = graph.get(path.get(path.size()-1));
			//换乘站且不是终点站
			if(sta1.getName().equals(sta2.getName()) && sta2.getId() != temp.getId())
			{
				
				//获取换乘方向
				String direction = getTransferDirection(sta2,path.get(i+2));
				result.add(sta1.getName()+"(换乘"+sta2.getLine()+"号线,"+direction+")");
				
				i++;
			}
			//换乘站,且换乘站为终点站
			else if(sta1.getName().equals(sta2.getName()))
			{
				//result.add(sta1.getName());
			}
			else
			{
				result.add(sta1.getName());
			}
		}
		
		result.add(graph.get(path.get(path.size()-1)).getName());
		if(path.size()>1)
		{
			String direction = getTransferDirection(graph.get(path.get(0)),path.get(1));
			result.set(0, result.get(0)+"("+startLine+","+direction+")");
		}
		else
		{
			result.set(0, result.get(0)+"("+startLine+")");
		}
		
		
		
		return result;
	}

	
	/**
	 * 获取起点站需要乘坐的路径,起点站为换乘,返回的是换乘站所有的下条线路
	 * @param path 路径
	 * @return 返回起点站需要乘坐的路径
	 */
	private String getStartLine(List<Integer> path) {
		// TODO Auto-generated method stub
		
		int n = 0;
		if(path.size()==1)
		{
			return "(已在目的地)";
		}
		Station sta1 = graph.get(path.get(n));
		Station sta2 = graph.get(path.get(n+1));
		while(sta1.getName().equals(sta2.getName()))
		{
			n++;
			sta1 = graph.get(path.get(n));
			sta2 = graph.get(path.get(n+1));
		}
		
		
		return "乘坐"+sta1.getLine()+"号线";
	}


	/**
	 * 获取换乘方向
	 * @param sta 换乘站
	 * @param nextId 换乘站的相邻车站id
	 * @return 换乘方向
	 */
	private String getTransferDirection(Station sta,Integer nextId) {
		// TODO Auto-generated method stub
		Line line = lineTable.get(sta.getLine());
		if(sta.getPrevSta()!=null && sta.getPrevSta().getId() == nextId)
		{
			return "往" + line.getStationList().get(0).getName() + "方向";
		}
		else if(sta.getNextSta()!=null && sta.getNextSta().getId() == nextId)
		{
			return "往" + line.getStationList().get(line.getStationList().size()-1).getName() + "方向";
		}
		else
		{
			return "";
		}
	}


	public List<Station> getGraph() {
		return graph;
	}




} 

 

测试类:

public static void main(String[] args) {
		// TODO 自动生成的方法存根
		try
		{
			long startTime = new Date().getTime();
			System.out.println("运行中....");
			PathSearch ps = new PathSearch();
			int start = 1;
			int end = 28;
			System.out.println("最短路:"+ps.getShortPath(start,end));
			System.out.println("换乘最少:"+ps.getTransferLessPathNoMakeAllPath(start,end));
			long endTime = new Date().getTime();
			System.out.print("耗时:"+(endTime-startTime)/1000.0+"秒");
		}
		catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		
		System.exit(0);
	}

}

 

版权声明:本文作者原创,未经允许不得他用,转载请注明出处。

  • 10
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
### 回答1: 在解决地铁网络上两站点最短路径问题时,可以使用算法。 一种常用的算法是 Dijkstra 算法,该算法通过比较从起点到各个结点的距离,不断更新最短路径。该算法从起点开始,每次选择到起点距离最近的未访问结点,标记为已访问,并使用该结点更新其他结点的距离。重复该过程,直到找到终点或所有结点均已访问。 另一种常用的算法是 A* 算法,该算法与 Dijkstra 算法类似,但在比较两个结点之的距离时,同时考虑当前距离与终点的估计距离,以便更快地找到最短路径。 这些算法都可以用来解决地铁网络上两站点最短路径问题,但是具体使用哪种算法取决于数据规模、计算复杂度等因素。 ### 回答2: 要解决地铁网络上两个站点之的最短路径问题,可以利用的最短路径算法。以下是算法设计的步骤: 1. 建立地铁网络的无向加权:将每个地铁站作为的一个节点,每条连接两个站点的地铁线路作为的一个边。每个边的权重可以是距离站点的距离或乘坐时。 2. 初始化算法:设定起点和终点站。 3. 使用Dijkstra算法找到最短路径:Dijkstra算法是解决单源最短路径问题的经典算法。它通过动态更新每个节点到起点的距离,逐步确定到达终点站的最短路径。具体步骤如下: - 设置起点站的距离为0,其他站点的距离为无穷大。 - 遍历的所有节点,选择距离起点最近的节点作为当前节点。 - 更新与当前节点相邻的节点的距离,如果通过当前节点到达相邻节点的距离比已有的距离小,则更新距离值。 - 重复上述步骤,直到遍历完所有节点或到达终点站为止。 4. 输出最短路径:根据Dijkstra算法得到的最短路径,输出起点到终点的最短路径。 通过以上算法设计,可以找到地铁网络上任意两个站点之的最短路径。 ### 回答3: 解决地铁网络上两站点最短路径问题常用的算法是Dijkstra算法。下面是具体的算法设计: 1. 构建地铁网络的模型:将每个地铁站作为的一个节点,将地铁线路或者换乘站作为的边。边的权重可以是两站点之的距离、时或者换乘次数等。 2. 初始化算法参数:设置起始站点为源点,其他站点均为未标记点。距离数组dist初始化为无穷大,标记数组visited初始化为false,路径数组path初始化为空。 3. 设置起始站点为当前节点,将其距离设为0,标记为已访问。 4. 遍历所有的相邻节点:对于当前节点的所有相邻节点,计算到相邻节点的距离,如果小于该节点之前的距离,则更新距离数组dist和路径数组path。 5. 选择下一个最短距离的节点:在未标记节点,选择距离最短的节点作为下一个当前节点,并将其标记为已访问。 6. 重复步骤4和步骤5,直到遍历完所有的站点。 7. 返回最终结果:根据路径数组path,可以生成从起始站点到目标站点的最短路径。 这样,通过Dijkstra算法可以解决地铁网络上两站点最短路径问题,并返回最短路径。该算法的时复杂度为O(V^2),其V为站点的数量。当地铁网络规模较大时,可以使用Floyd-Warshall算法或者A*算法等更优化的算法来解决。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值