华为笔试---理解回溯算法的搜索空间

在这里插入图片描述

题目描述:
无线设备传输过程中,数据经常需要通过各种中继设备进行中转。现有某段传输路径,每隔1km放置1个中继设备用于数据中转,现用一数组来描述包括起始点的所有中继设备的最大传输距离(单位km)。求从起点到终点,能完成信号传输的最少中转次数;

输入:
一个数组: [2 ,3 , 1, 1]
该数组表示有4个中转站,其中元素表示每个中转站最大传输距离。
例如,上面数组表示第一台中转站最大传输距离位2,第二台中转站最大传输距离为3, 第三台中转站最大传输距离为1,第四台中转站最大传输距离为1。

输出:
从起点到终点,能完成信号传输的最少中转次数;

对于例1:
输入: 2 3 1 1
输出为: 2
说明:
1.最小中转方式:从1号设备中转到2号设备,2号设备直接到达4号设备
2.其他中转方式: 1号->2号-3号->4号, 需要3次中转;非最小;

拿到题目首先分析题目:
首先分析输入和输出。上文已经分析过了。

对于我当时的思考,当时就想用动态规划的思想,但是分析发现,最小子问题不具有最优子结构。因此就没有用动态规划,于是选择了用回溯算法

回溯算法的思想就是,深度优先搜索找到所有可能的解,从而找到最优。

先分析一个例子
当输入为[2, 3, 1, 1],其回溯图如下所示。
在这里插入图片描述
在这个题目中,最需要注意的就是每一层的搜索空间下一层的搜索空间,取决于上一层的选择
因为第一台中转站必须要经过,因此第一台不做讨论。当经过第二台时,他接着有两条路可以选择(3或 4 中转站)
因此就可以编写代码,其中用了trace记录每次选择的中转站编号。

    /**
     *
     * @param nums
     * @param
     * @param trace  选择的路径
     */
    public static void  helper(int[] nums, LinkedList<Integer> trace){

        // boundary
        if (trace.getLast() == nums.length - 1){
            max = Math.min(max, trace.size() - 1);
            System.out.println(trace.toString());  // 打印选择的路径
            return;
        }

        // search( 此处的搜索空间,就依赖于上一层选择的中转站)
        for (int i = trace.getLast() + 1; i <= Math.min(nums[trace.getLast()] + trace.getLast(), nums.length-1); ++i){
		     trace.add(i);
		      helper(nums,  trace );
		      trace.removeLast();
        }
    }

整个函数运行的代码为:

    static int max = Integer.MAX_VALUE;


    public static void main(String[] args) {
        int[]  nums = {2, 3, 1, 1};
        LinkedList trace = new LinkedList<Integer>();
        trace.add(0); // 初始值(因为中转站台1必选【对应数组索引0】)

        helper(nums, trace);

        System.out.println(max);
    }

最后结果为:
在这里插入图片描述
上面表示选择的路径;
最下面一行表示最小中转次数为:2

多次测试
输入:
int[] nums = {4, 1, 2, 3, 1, 1, 1, 2, 3, 1, 1};
输出为:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
经过运算,可以很清晰看到走过的路径。
但是整个计算量比较大。因此有没有优化的可能性?
因为每次我们都是逐个选择,并比较。

可以在添加利用一条规则,就是在每次的选择过程中,尽可能选择传输距离最远的站台,如果没有(即传输距离都一样),则选择当前站台可以达到的最远站台。【有点类似贪心算法,局部最优选择】

改进后的代码:

    public static void  helper(int[] nums, LinkedList<Integer> trace){

        // boundary
        if (trace.getLast() == nums.length - 1){
            max = Math.min(max, trace.size() - 1);
            System.out.println(trace.toString());
            return;
        }

        int index = trace.getLast() + 1;  // 起始选择站台
        // search
        for (int i = trace.getLast() + 1; i < Math.min(nums[trace.getLast()] + trace.getLast(), nums.length-1); ++i){
            if (nums[i] <= nums[i + 1]){
                index = i + 1;     // 找到传输距离最远的站台
            }
        }
        // 直接一步跳到最后一个站台
  		if (Math.min(nums[trace.getLast()] + trace.getLast(), nums.length-1) == nums.length-1){
            index = nums.length -1;
        }

        //            System.out.println("当前路径的最后一个:" + trace.getLast());

        trace.add(index);
        helper(nums,  trace );
        trace.removeLast();
    }

测试
输入:
int[] nums = {4, 1, 2, 3, 1, 1, 1, 2, 3, 1, 1};(和上面测试实例相同)
输出为:
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值