迷宫中回溯法的剪枝——奇偶剪枝

问题描述

在一个n行m列的迷宫中,每一步只能向上、下、左、右中任意方向走一格,迷宫中有围墙的地方是无法到达的。从起点s开始,能否刚好走t步,到达e。

例如在下面5行5列的迷宫中,能否恰好经过9步,从s走到e。初始位置在s上,#是围墙。



奇偶剪枝

设起点s的坐标为(sx,sy),终点e的坐标为(ex,ey);

对s的一次操作为对sx或sy进行+1或-1;

若经过t次操作后,s的坐标刚好等于e,则说从s经过t步可以到达e。

在理想情况下,s到e需要的最小步数为m

m=|ex-sx|+|ey-sy|

若t<m,肯定是无法到达的。

当t>=m时,从s到e的行走路径由两部分组成,

一部分为需要走的最少步数m;

另一部分是为了使得刚好行走t步到达e,所需要走的附加步数a,a=t-m;

这a步即为:从需要走m步的最短路径上走出去,再回到最短路径上所走的步数。

假设走出去这段路径长度为b,那回来时的路径长度一定也是b,因此,附加步数的路径长度a等于2b步。

因为走出去时,对坐标进行了b次+1或-1的操作,为使坐标再恢复到最短路径上,就需要进行b次-1或+1的操作,并且与走出去时是相反的。注意:走出去和拐回来的过程中可能参杂着最短路径上的操作,所以b是除去这些参杂操作后的步数。

如下图所示:


从s到e的黑色路径为一条最短路径,红色和蓝色路线组成的路径,为走出最短路径的路径。其中蓝色箭头是参杂着的最短路径中的操作,只有红色箭头才是走出去和拐回来的路径,如果将红色路径去掉,从s向右走,经过绿色箭头到达e,这也是一条最短路径。

因为a=2b,是个偶数,又因为a=t-m,所以当t和m的奇偶性相同时,a才能是偶数。也就是说,当t和m的奇偶性相同时,才有可能从s经过t步,到达e。

所以,当最小步数m与t同为奇数,或同为偶数时,才有可能从s经过t步,到达e。

  • 10
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
01背包问题是一个经典的动态规划问题,其基本思想是:用有限的容量装下最大价值的物品。回溯是一种基于深度优先搜索的算,可以用于解决这个问题。回溯的基本思路是:在搜索过程,当发现当前状态已经无继续得到最优解时,就立即返回上一层进行剪枝,以减少搜索次数,提高效率。 在01背包问题回溯剪枝可以通过以下几个方面实现: 1. 首先,可以根据当前的物品体积和重量,计算出当前可选的物品能够达到的最大价值,如果这个价值已经小于当前最优解的价值了,就可以直接返回上一层进行剪枝。 2. 其次,在选择某个物品时,可以根据当前所选物品的体积和重量,计算出还有剩余容量能够获得的最大价值,如果这个价值加上已经选择的物品的价值,仍然小于当前最优解的价值,就可以直接返回上一层进行剪枝。 3. 最后,在搜索过程可以记录已经搜索过的状态,避免重复搜索同样的状态,减少搜索次数。 下面是一份Java代码示例,展示了如何使用回溯解决01背包问题并实现剪枝: ``` public class Knapsack { private int maxV = Integer.MIN_VALUE; // 最大价值 private int[] w; // 物品重量 private int[] v; // 物品价值 private int n; // 物品数量 private int c; // 背包容量 public int max(int a, int b) { return a > b ? a : b; } // i表示考察到哪个物品了,cw表示当前已经装进去的物品重量和;cv表示当前已经装进去的物品价值和 public void dfs(int i, int cw, int cv) { if (cw == c || i == n) { // 装满了或者考察完了所有物品 if (cv > maxV) maxV = cv; return; } dfs(i + 1, cw, cv); // 不装第i个物品 if (cw + w[i] <= c) { // 装得下第i个物品 // 剪枝1:如果当前最大价值已经小于等于当前可选物品的最大价值,则不需要再继续搜索 if (cv + v[i] + maxV(cv + v[i], i + 1, cw + w[i]) <= maxV) return; dfs(i + 1, cw + w[i], cv + v[i]); // 装第i个物品 } } // 计算剩余物品能够获得的最大价值 public int maxV(int cv, int i, int cw) { int maxv = 0; for (int j = i; j < n; j++) { if (cw + w[j] <= c) { cw += w[j]; cv += v[j]; } else { maxv = (c - cw) * v[j] / w[j]; // 装满剩余容量可以获得的最大价值 break; } } return maxv; } public static void main(String[] args) { Knapsack k = new Knapsack(); k.w = new int[]{2, 2, 4, 6, 3}; k.v = new int[]{3, 4, 8, 9, 6}; k.n = 5; k.c = 9; k.dfs(0, 0, 0); System.out.println(k.maxV); } } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

庞老板

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

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

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

打赏作者

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

抵扣说明:

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

余额充值