HNU算法设计与分析实验二(安全专业)

3-7 汽车加油行驶问题

问题描述

给定一个NxN的方形网格,设其左上角为起点O,坐标为(1,1),X轴向右为正.y轴向下为正,每个方格边长为1。一辆汽车从起点0出发驶向右下角终点▲,其坐标为(N,N)。在若干网格交叉点处,设置了油库,可供汽车在行驶途中加油。汽车在行驶过程应遵守如下规则:

(1)汽车只能沿网格边行驶,装满油后能行驶K条网格边。出发时汽车已装满油,在起点和终点不设油库  

(2)当汽车行驶经过一条网格边时,若其X坐标或坐标减小,则应付费用B,否则免付费用

(3)汽车在行驶过程中遇油库则应加满油并付加油费用A

(4)在需要时可在网格点处增设油库,并付增设油库费用C(不含加油费用A)

(5)N,K,A,B,C均为整数

算法设计

求出汽车从起点到终点的一条付费最小的行驶路线

数据输入

由文件input.txt提供输入数据。文件的第1行是N,K,A,B,C的值,2<N<100,2<K<10。第2行起是一个NxN的0-1方阵,每行N个值,至N+1行结束。方阵的第i行第广列处的值为1表示在网格交叉点(i,j)处设置了一个油库,为0时表示未设油库。各行相邻的2个数以空格分隔。

结果输出

将找到的最优行驶路线所需的费用即最小费用输出到文件output.txt。文件的第1行中的数是最小费用值。

示例输入                               输出示例

9 3 2 3 6                              12

0 0 0 0 1 0 0 0 0

0 0 0 1 0 1 1 0 0

1 0 1 0 0 0 0 1 0

0 0 0 0 0 1 0 0 1

1 0 0 1 0 0 1 0 0

0 1 0 0 0 0 0 1 0

0 0 0 0 1 0 0 0 1

1 0 0 1 0 0 0 1 0

0 1 0 0 0 0 0 0 0

算法实现与思路分析

  1. 回溯法(DFS+剪枝)

核心思路

递归探索:递归遍历所有可能的路径,记录每条路径的费用

剪枝优化:若当前费用≥已知最小费用,或当前费用已经不是最优(高于dp值,终止递归)

核心代码

性能分析

时间复杂度:最坏情况下非常大,可超过指数级,尽管我们进行了剪枝,效果依然比较差。

空间复杂度:O(N+K)(递归深度:最短路径是2N-2步(全向右和向下),最长路径(如绕路)不会超过O(N²);而每次满油,也最多行驶K步,当油耗尽后会重新递归,更新递归深度),考虑dp数组则为O(N²K)

  1. BFS(队列+dp)

核心思路

用(x,y,r)和dp[x][y][r]记录状态和费用

按照先入先出的顺序处理,(相当于对树结构进行层次遍历)

状态转移时通过dp数组排除高费用状态

核心代码

性能分析

时间复杂度:最坏情况下O (N²・K × 2^(N+K))(指数级)。由于队列无序,同一状态可能被多次加入(费用递增),无效操作极多:

网格大小为N×N,油量上限为K,则:

  1. 状态总数:最多为N×N×(K+1)(每个坐标N×N,油量0~K)。
  2. 每个状态的入队次数:在最坏情况下,每个状态可能被指数级次数入队。例如,若每次到达同一状态的费用都比之前低(但 BFS仍会处理所有历史状态),入队次数可能达到O(2^(N+K))(随路径长度指数增长)。
  3. 每次入队的处理成本:每个状态需要尝试 4 个方向的移动(O(1)操作)。

因此,总时间复杂度为:状态总数 × 平均入队次数 × 单次处理成本 ≈ O (N²・K × 2^(N+K)),这是一个指数级复杂度。

空间复杂度:dp数组O(N²K)

  1. Dijkstra(优先队列+dp)

核心思路

同理用状态表示,但是我们将队列换为优先队列,可以避免许多高费用状态的重复访问,更快得到结果

我们在此基础上还有一步优化:在遍历时考虑到,我们其实应该是尽量避免新建加油站的(一方面加油次数要尽可能少,因为每次加油不论剩余油量耗费是一样的,另一方面由于每次路过加油站一定要加油,故新建加油站是非常不划算的),所以在剩余油量达到0之前我们都可以避免新建加油站。

核心代码

该部分是状态结构体,并且定义了优先队列按最小堆来实现

性能分析

时间复杂度:O (N²・K・log (N²・K))。状态总数为 N²・K(每个坐标 N×N,油量K+1个状态),优先队列每次操作复杂度为 log (状态总数),每个状态扩展 4 个方向(O (1))。

空间复杂度: dp数组O(N²K)

测试

对参考测试样例进行测(比较三者的速率)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值