深度优先搜索解最短路径------PAT甲级1003题

本文介绍了一种利用深度优先搜索(DFS)算法求解图中两点间最短路径的方法,并通过一个具体题目展示了如何实现这一算法。文章还讨论了如何在搜索过程中进行剪枝以提高效率。

        
        先讨论一般情况下的深度优先搜索求解最短路径。其实就是借助DFS的思想穷举所有从起点到终点的路径,当找到一条路径后进行判断,如果满足我们希望找到的路径,则返回。如果当前访问的点不是终点,就遍历以该点为起点时能到达的点,如果这个能到达的点不在当前路径上,则递归走这个点。在不停的递归中我们需要一种数据结构来保存路径,这里用了C++STL的vector,要注意的是在递归访问下一个点前我们要把下一个点加入到vector中,当访问过后要把这个点从路径中去掉。主要的函数结构大概如下:
        
void DFS(int node)
{
	if(node == 终点)
	{
		当前访问的node等与终点,说明找到了一条从起点到终点的路径,但还不知道
		是不是我们需要的路径,需要从保存路径的vector中提取相关信息,比如路径
		的长度,路径上各点的点权之和等等,根据需要保存到全局变量中。 
		return; 
	}
	如果当前访问的节点不是终点说明要以此点为新的出发点继续寻找路径 
	for(寻找下一个点,看你是邻接矩阵还是邻接表,并且这个点不能是已在路径上的点)
	{
		找到了下一个点i,准备访问i之前要将i加入路径,然后递归访问i,访问之后
		要将i从路径中去掉, 
	}  
}

        下面给出只求路径最短的源码:
        
const int maxn;		//节点个数 
vector<int> path;	//储存路径的向量 
int dis=10000000,destination;//存放最小距离的dis,表示终点的destination 
int map[maxn][maxn];	//邻接矩阵 
int hash[maxn]={0};		//哈希数组  方便判断要访问的点是否已在路径中 

//参数currant表示当前访问的点 
void DFS(int current)
{
	//如果当前访问的点到了终点,说明找到了一条路径 
	if(current == destination)
	{	
		//临时变量存放该路径的距离大小 
		int tmp_dis=0;	
		
		//路径上的n个点有n-1条路,把它们的长度加起来 
		for(int i=0;i<path.size()-1;i++) tmp_dis += map[path[i]][path[i+1]];
		
		//如果这个临时距离比已知的最小路径小,则更新dis 
		if(tmp_dis<=dis) dis = tmp_dis;
		return;
	}
	for(int i=0;i<maxn;i++)
	{
		//如果从当前点current到点i有路,并且i尚未在路径中 
		if(map[current][i]!=0 && hash[i]==0)
		{
			//将下一步点i加入路径向量 
			path.push_back(i);
			
			//设置下一步已访问 
			hash[i] = 1;
			
			//递归继续寻找路径 
			DFS(i);path.pop_back();
			
			//i点使用完后设置它尚未访问 
			hash[i] = 0;
		}
	}
}

        这种写法比较简陋,还可以进一步剪枝。因为此时我们是只有找到了一条路径才计算这条路径是否满足要求,在寻找路径的过程中,如果走下一步点i,使得当前路径的距离值比已知的最小距离要大,就不用递归走i点了。

        最后我们结合PAT甲级1003题用DFS求解。

        该题要求下若有多条最短路径则需要点权和最大的一条。只需在最短路径结算的部分加一些判断即可。以下为解答代码:
        
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn=510;
vector<int> path;
int dis=10000000,sum=0,start_p,destination;
int n,m;
int map[maxn][maxn],weight[maxn]; 
int hash[maxn]={0};
void DFS(int start)
{
	if(start == destination)
	{	
		
		int tmp_dis=0,tmp_weight=0;
		for(int i=0;i<path.size()-1;i++)
		{
			tmp_dis += map[path[i]][path[i+1]];
			tmp_weight += weight[i];
		}
		tmp_weight += weight[destination];
		if(tmp_dis<=dis)
		{
			dis = tmp_dis;
			if(tmp_weight>sum) sum = tmp_weight;
			
		}
		return;
	}
	for(int i=0;i<n;i++)
	{
		if(map[start][i]!=0 && hash[i]==0)
		{
			path.push_back(i);
			hash[i] = 1;
			DFS(i);path.pop_back();
			hash[i] = 0;
		}
		
	}
}
int main()
{
	FILE * f;
	f = fopen("test.txt","r");
	fscanf(f,"%d %d %d %d",&n,&m,&start_p,&destination);
	for(int i=0;i<n;i++)
	{
		fscanf(f,"%d",&weight[i]);
	}
	int s,e,d;
	for(int i=0;i<m;i++)
	{
		fscanf(f,"%d %d %d",&s,&e,&d);
		map[s][e] = d;
		map[e][s] = d;
	}
	path.push_back(start_p);
	hash[start_p] = 1;
	DFS(start_p);
	cout<<dis<<" "<<sum<<endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值