DFS:寻路问题

题目

N个城市,编号1到N。城市间有R条单向道路。 
每条道路连接两个城市,有长度和过路费两个属性。 
Bob只有K块钱,他想从城市1走到城市N。问最短共需要走多长的路。如果到不了N,输出-1。

· S is the source city, 1 <= S <= N 

· D is the destination city, 1 <= D <= N 

· L is the road length, 1 <= L <= 100 

· T is the toll (expressed in the number of coins), 0 <= T <=100


Notice that different roads may have the same source and destination cities.

Output

The first and the only line of the output should contain the total length of the shortest path from the city 1 to the city N whose total toll is less than or equal K coins. 
If such path does not exist, only number -1 should be written to the output. 

Sample Input

5

6

7

1 2 2 3

2 4 3 3

3 4 2 4

1 3 4 1

4 6 2 1

3 5 2 0

5 4 3 2

Sample Output

11

在这里插入图片描述

解题思路

从城市1开始深度优先遍历整个图,找到所有能到达N的走法,选一个最优的

剪枝:
#inclue<iostream>
#inclue<vector>
#inclue<cstring>
using namespace std;
//首先定义三个全局变量,钱数,城市数,道路数
int K,N,R;
//我们用领接表来存放整个图
//存放一条边的信息
struct Road{
//终点,长度,过路费
	int d,L,t;
}//领接表,数组套数组,vector套vector
//G是一个vector,110个元素,每一个元素又是另一个vector,
vector<vector<Road>>G(110);//或者说可以说是一个二维数组,有110行,每一行都是一个一维数组vectorroad,每一个元素都是road对象,g开始每一行数组都是空的,领接表的个数是不同的
//G[i]是一个一维数组,存放从i这个节点连出去的边,每个边用road表示,所以road都不用记录起点,起点为g[i]
//G[i]

//记录到目前为止找到最佳到终点路径的长度
int minLen;
//我正在走的这条路有多长
int totalLen;
//我正在走的这条路花了多少钱
int totalCost;
//记录一个城市是否走过
int visited[110];

int mian(){
	//录入
	cin>>k>>N>>R;
	//把R条边存入
	for(int i=0;i<R;i++){
		//边的起点
		int s;
		//边的信息
		Road r;
		//编入起点s,终点d,长度l,过路费t
		cin>>s>>r.d>>r.L>>r.t;
		//在起点不等于终点
		if(s!=r.d){
		//G[s]存放起点为s里面,r放进g[s]一维数组里面,每读到一条就加一个边
			G[s].push_back(r);
		}
		
	}
	//初始化
	memset(visited,0,sizeof(visited));
	totalLen=0;
	//minLen等于一个很大的数
	minLen=1<<30;
	totalCost=0;
	//1号点开始进行深度优先搜索,
	visited[1]=1//从1号点开始搜索
	dfs(1);
	//结束完了说明找出的工作结束了
	//找出来的最优路径的长度都放在minLen,当然也有可能找不打最优解
	//当MinLen小于初始的最大值,我们找到了路
	if(minLen<(1<<30)){
		cout<minLEN<<endl;
	}
	else
		cout<<"-1"<<end1;
}

void dfs(int s){
//首先判断是不是走到终点
	if(s==N){
	//找到一个新的路,要判断是不是最小,所以有一个更新的操作
		minLen =min(minLen,totalLen);
		return ;
	}
	//从s出发进行深度优先搜索
	for(int i=0;i<G[s].size();i++){
		Road r=G[s][i];//这条边
		//要先判断我有没有足够的前走到road.d
		//可行性剪枝用了一部分,我们还可以用上最优性剪枝
		if(totalCost+r.t>k)
			continue;
		//必须没走过才能走过
		if(!visitd[r.d[){
		//增加长度
			totalLen+=r.L;
			//增加开销
			totalCost+=r.t;
			visited[r.d]=1;
			dis(r.d);
			//不走r.d走别的路,要撤销
			visited[r.d]=0;
			totalLen-=r.L;
			totalCost-=r.t;
		}	
		
	}
}

在java中没有struct
Java 中的 Class 对象体现的就是 Struct 结构体的思想。虽然 C 语言是一个面向过程化的语言,不过这个 Struct 结构体却面向对象的味道,而 Java 做为面向对象的语言,要实现 Struct

最优性剪枝

在这里插入图片描述

#inclue<iostream>
#inclue<vector>
#inclue<cstring>
using namespace std;
//首先定义三个全局变量,钱数,城市数,道路数
int K,N,R;
//我们用领接表来存放整个图
//存放一条边的信息
struct Road{
//终点,长度,过路费
	int d,L,t;
}//领接表,数组套数组,vector套vector
//G是一个vector,110个元素,每一个元素又是另一个vector,
vector<vector<Road>>G(110);//或者说可以说是一个二维数组,有110行,每一行都是一个一维数组vectorroad,每一个元素都是road对象,g开始每一行数组都是空的,领接表的个数是不同的
//G[i]是一个一维数组,存放从i这个节点连出去的边,每个边用road表示,所以road都不用记录起点,起点为g[i]
//G[i]
//最小路径
int minL[110][10010];
//记录到目前为止找到最佳到终点路径的长度
int minLen;
//我正在走的这条路有多长
int totalLen;
//我正在走的这条路花了多少钱
int totalCost;
//记录一个城市是否走过
int visited[110];

int mian(){
	//录入
	cin>>k>>N>>R;
	//把R条边存入
	for(int i=0;i<R;i++){
		//边的起点
		int s;
		//边的信息
		Road r;
		//编入起点s,终点d,长度l,过路费t
		cin>>s>>r.d>>r.L>>r.t;
		//在起点不等于终点
		if(s!=r.d){
		//G[s]存放起点为s里面,r放进g[s]一维数组里面,每读到一条就加一个边
			G[s].push_back(r);
		}
		
	}
	//初始化
	memset(visited,0,sizeof(visited));
	totalLen=0;
	//minLen等于一个很大的数
	minLen=1<<30;
	totalCost=0;
	//1号点开始进行深度优先搜索,
	visited[1]=1for(int i=0;i<110;i++)
		for(int j=0;j<10010;j++)
		min[i][j]<<30;
//从1号点开始搜索
	dfs(1);
	//结束完了说明找出的工作结束了
	//找出来的最优路径的长度都放在minLen,当然也有可能找不打最优解
	//当MinLen小于初始的最大值,我们找到了路
	if(minLen<(1<<30)){
		cout<minLEN<<endl;
	}
	else
		cout<<"-1"<<end1;
}

void dfs(int s){
//首先判断是不是走到终点
	if(s==N){
	//找到一个新的路,要判断是不是最小,所以有一个更新的操作
		minLen =min(minLen,totalLen);
		return ;
	}
	//从s出发进行深度优先搜索
	for(int i=0;i<G[s].size();i++){
		Road r=G[s][i];//这条边
		//要先判断我有没有足够的前走到road.d
		//可行性剪枝用了一部分,我们还可以用上最优性剪枝
		if(totalCost+r.t>k)
			continue;
		//必须没走过才能走过
		if(!visitd[r.d[){
		//最优性剪枝
		if(totalLen+r.L>=minLen)
			continue;//这样子我们没必要再往下计算了
		if(totalLen+r.L>=minL[r.d][totalCost+r.t])
			continue;
		//如果剪枝不成立,还要更新minL[r.d]
		minL[r.d][totalCost+r.L]=totalLen+r.L;
		//增加长度
			totalLen+=r.L;
			//增加开销
			totalCost+=r.t;
			visited[r.d]=1;
			dis(r.d);
			//不走r.d走别的路,要撤销
			visited[r.d]=0;
			totalLen-=r.L;
			totalCost-=r.t;
		}	
		
	}

在这里插入图片描述

#inclue<iostream>
#inclue<vector>
#inclue<cstring>
using namespace std;
//首先定义三个全局变量,钱数,城市数,道路数
int K,N,R;
//我们用领接表来存放整个图
//存放一条边的信息
struct Road{
//终点,长度,过路费
	int d,L,t;
}//领接表,数组套数组,vector套vector
//G是一个vector,110个元素,每一个元素又是另一个vector,
vector<vector<Road>>G(110);//或者说可以说是一个二维数组,有110行,每一行都是一个一维数组vectorroad,每一个元素都是road对象,g开始每一行数组都是空的,领接表的个数是不同的
//G[i]是一个一维数组,存放从i这个节点连出去的边,每个边用road表示,所以road都不用记录起点,起点为g[i]
//G[i]

int minL[110][10010];

//记录到目前为止找到最佳到终点路径的长度
int minLen;
//我正在走的这条路有多长
int totalLen;
//我正在走的这条路花了多少钱
int totalCost;
//记录一个城市是否走过
int visited[110];

int mian(){
	//录入
	cin>>k>>N>>R;
	//把R条边存入
	for(int i=0;i<R;i++){
		//边的起点
		int s;
		//边的信息
		Road r;
		//编入起点s,终点d,长度l,过路费t
		cin>>s>>r.d>>r.L>>r.t;
		//在起点不等于终点
		if(s!=r.d){
		//G[s]存放起点为s里面,r放进g[s]一维数组里面,每读到一条就加一个边
			G[s].push_back(r);
		}
		
	}
	//初始化
	memset(visited,0,sizeof(visited));
	totalLen=0;
	//minLen等于一个很大的数
	minLen=1<<30;
	totalCost=0;
	//1号点开始进行深度优先搜索,
	visited[1]=1//从1号点开始搜索
	dfs(1);
	//结束完了说明找出的工作结束了
	//找出来的最优路径的长度都放在minLen,当然也有可能找不打最优解
	//当MinLen小于初始的最大值,我们找到了路
	if(minLen<(1<<30)){
		cout<minLEN<<endl;
	}
	else
		cout<<"-1"<<end1;
}

void dfs(int s){
//首先判断是不是走到终点
	if(s==N){
	//找到一个新的路,要判断是不是最小,所以有一个更新的操作
		minLen =min(minLen,totalLen);
		return ;
	}
	//从s出发进行深度优先搜索
	for(int i=0;i<G[s].size();i++){
		Road r=G[s][i];//这条边
		//要先判断我有没有足够的前走到road.d
		//可行性剪枝用了一部分,我们还可以用上最优性剪枝
		if(totalCost+r.t>k)
			continue;
		//必须没走过才能走过
		if(!visitd[r.d[){
		//最优性剪枝
		if(totalLen+r.L>=minLen)
			continue;//这样子我们没必要再往下计算了
			
		//增加长度
			totalLen+=r.L;
			//增加开销
			totalCost+=r.t;
			visited[r.d]=1;
			dis(r.d);
			//不走r.d走别的路,要撤销
			visited[r.d]=0;
			totalLen-=r.L;
			totalCost-=r.t;
		}	
		
	}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向上Claire

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值