DFS:寻路问题(Roads)

POJ 1724 寻路问题(Roads)

描述

将由数字1到N标记的城市用单行道相连,每条道路都有两个相关参数:道路长度和需要为道路支付的通行费(用硬币的数量表示)。鲍勃和爱丽丝过去住在城市1里。在注意到爱丽丝在他们喜欢玩的纸牌游戏中作弊后,鲍勃和她分手了,并决定搬到N城市去。他想尽快赶到那里,但他手头没钱。
我们想帮助Bob找到从城市1到城市N的最短路径,只要他有足够的钱。

输入

输入的第一行包含整数K, 0 <= K <= 10000, Bob在途中可以花费的最大硬币数。
第二行包含整数N, 2 <= N <= 100,城市总数。
第三行包含整数R, 1 <= R <= 10000,道路总数。
下面的每一行通过指定由单个空白字符分隔的整数S, D, L和T来描述一条路:

  • S为源城市,1 <= S <= N

  • D为目的地城市,1 <= D <= N

  • L是道路长度,1 <= L <= 100

  • T为通行费(用硬币数量表示),0 <= T <=100

注意:不同的道路可能有相同的源城市和目的地城市。

输出

输出唯一 一行应该包含从城市1到城市N的最短路径的总长度并且到达城市N的总通行费小于或等于K个硬币。
如果这样的路径不存在,则输出-1。

样例输入

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

样例输出

11

解题思路

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

剪枝操作:

  1. 如果当前已经找到的最优路径长度为L ,那么在继续搜索的过程中,总长度已经大
    于L的走法,就可以直接放弃,不用走到底了
  2. 用minL[k][m] 表示:走到城市k时总过路费为m的条件下,最优路径的长度。若在
    后续的搜索中,再次走到k时,如果总路费恰好为m,且此时的路径长度已经超过
    minL[k][m],则不必再走下去了。
#include <iostream>
#include <vector>
using namespace std;

int K,N,R;//定义Bob拥有的总钱数,城市总数,道路总数
struct Road {
    
    
 	int S, D, L, T;
};//定义源城市,目的地城市,道路长度,通行费
vector< vector<Road> > cityMap(110); //邻接表,cityMap[i]是从点i有路连到的城市集合,此处邻接表和二维数组差不多 
int totalLen, totalCost; //正在走的路径的长度和花销
int minLen = 1 << 30; //初始化开始最优路径的长度为一超级大的数 
int visited[110]; //城市是否已经走过的标记
int minL[110][10100]; //minL[i][j]表示从1到i点的,花销为j的最短路的长度

void DFS(int s) //从s开始向N行走
{
    
    
	if(s == N) 
	{
    
    
		minLen = min(minLen,totalLen);
		return;
	}//证明已经到达终点并走完全程了,接下来和之前找到的最短路径进行比较 
	
	for(int i = 0;i < cityMap[s].size();i++) 
	{
    
    
		int d = cityMap[s][i].D; //S有路连到D
		if(!visited[d]) 
		{
    
    
			int cost = totalCost + cityMap[s][i].T;
			
			if(cost > K) continue;//超过最大金额就放弃该条路 
			if(totalLen + cityMap[s][i].L >= minLen||totalLen + cityMap[s][i].L >= minL[d][cost])
			continue;//搜索过程中加上下一条路的长度已经大于之前得到的最小路径就放弃这种走法(与之前搜索结果相比) 
					//或者到达同一目的城市花销相同但路径大于之前记录下的最小路径就放弃这种走法(与之前搜索某过程相比)
		
			//选择走该条路 
			totalLen += cityMap[s][i].L;
			totalCost += cityMap[s][i].T;
			minL[d][cost] = totalLen;
			visited[d] = 1;
			DFS(d);//从d点继续深度优先搜索 
			
			//DFS的意思是从s走到d再接下来的走法,但也可以不走d,在其他走法中可能绕回d
			//故此走其他点,不走d,要把visited,totalCost,totalLen恢复到走d之前的值 
			visited[d] = 0;
			totalCost-= cityMap[s][i].T;
			totalLen-= cityMap[s][i].L;
			 
		}
	}
}
int main() {
    
    
	
	cin >>K >> N >> R;//分别输入Bob拥有的总钱数,城市总数,道路总数 
	for(int i = 0;i < R; i++) 
	{
    
    
		Road r;
		cin >> r.S >> r.D >> r.L >> r.T;
		if( r.S != r.D ) cityMap[r.S].push_back(r);//记录单向道路 
	}
	for(int i = 0;i < 110; i++ )
		for(int j = 0; j < 10100;  j++ )
			minL[i][j] = 1 << 30;
	visited[1] = 1;
	DFS(1);//从第1个城市出发,找到最优路径后会更新minLen 
	
	if(minLen < (1 << 30)) cout << minLen << endl;
	else cout << "-1" << endl;
}

猜你喜欢

转载自blog.csdn.net/m0_51354361/article/details/113251002
今日推荐