• poj3009


    原题链接:http://poj.org/problem?id=3009

    这道题目中文的描述大概是有一冰球,可以前后左右击打它,不能出边、不能一开始就碰壁、不能斜着走,极大后除非遇到边才能停下来,停下来后墙壁裂开(这个地方应该是为了防止重复运动),直到遇到终点,终点是一个摩擦力巨大的位置,所以只要行进轨道中存在该终点则游戏结束,不可高于十次击打。求最少的到达终点的击打次数。

    部分配图如下,这是题目给出的例图,S为起点,G为终点

                                      

    这里讲一下我们的思路

    寻找最小的路径来通往终点,首先我们定义一个地图,0为空地、1为墙壁、2为起点、3为终点,在算法开始前,先将该起点位置保存,并将该位置置为空地,getStartFlag和getEndFlag用于提前结束寻找起点与终点循环,函数isLegal用于判断现在的情况下的棋子位置是否合法。深度优先遍历的逻辑如下:结束判断为:如果现在的起点位置正好是终点位置,那么说明现在正好是找到了最终点,那么退出;而如果此时的步数answerStep大于十或大于另设的最大阈值了,那么也退出。每次对下一步进行循环的时候,都要做一件事情=>对四个方向进行遍历,所以这里我们用一个向量数组表示我们位移的方向。那么对单一方向进行位移的过程中,我们用now对象来储存当前的位置,一直循环直到碰壁或接触到终点,碰壁则退出循环,终点则结束。退出循环后当然还要进行一次判断,判断该次位移是否只“移动了一位”,这里判断只移动了一位的原因是,在题目中不能往紧贴墙的位置击打,同时我们由于碰壁退出循环的条件是当前的map[now.x][now.y] == 1,所以若只位移了一次,说明这次的位移是“撞碎紧贴墙壁”造成的位移,所以如果是这样的话,我们就要进行下一个方向的位移阶段了。那么若是不是“撞碎紧贴墙壁”造成的位移,那么这次位移我们可以认为是OK的,我们将这里的map置为0,让start位移到这里,并减去一个单位的d向量(因为其实我们现在是在碎墙上),继续下一次的查找。每次函数退出,会将刚才的地图置为1,步数减一,视为悔步。

    所以我们的代码如下,使用的是JS的语法,但是用其他语言也是OK的,没有什么需要特别注意的地方,大家如果有什么不懂的地方可以在评论区询问我哦

    // poj3009
    let map = [
        [1, 0, 0, 2, 1, 0],
        [1, 1, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 3],
        [0, 0, 0, 0, 0, 0],
        [1, 0, 0, 0, 0, 1],
        [0, 1, 1, 1, 1, 1],
    ];
    let width = 6;
    let height = 6;
    
    //起始
    let start = {};
    //目标
    let end = {};
    // 简化调试步骤
    let getStartFlag = false;
    let getEndFlag = false;
    // 移动的向量
    let d = [[-1, 0], [1, 0], [0, -1], [0, 1]];
    let result = 11;
    
    for (let i = 0; i < height; i++) {
        for (let j = 0; j < width; j++) {
            if (getStartFlag && getEndFlag) {
                break;
            }
            if (map[i][j] == 2) {
                start.x = i;
                start.y = j;
                map[i][j] = 0;
                getStartFlag = true
            }
            if (map[i][j] == 3) {
                end.x = i;
                end.y = j;
                getEndFlag = true
            }
        }
    }
    
    dfs(start, 0);
    console.log(`${result == 11 ? '-1' : result}`);
    
    function dfs(start, answerStep) {
        // 该函数判断该now位置是否合法
        let isLegal = now => (0 <= now.x && 0 <= now.y && now.x < height && now.y < width);
        // 结束判断
        if (start.x == end.x && start.y == end.y) {
            if (result > answerStep) {
                result = answerStep;
            }
            return;
        }
        // 结束判断
        if (answerStep == 10 || answerStep >= result) {
            return;
        }
        // 对四个方向进行循环
        for (let i = 0; i < 4; i++) {
            let now = {}
            now.x = start.x + d[i][0];
            now.y = start.y + d[i][1];
            // 对单一方向的深入
            while (isLegal(now) && map[now.x][now.y] != 1) {
                if (now.x == end.x && now.y == end.y) {
                    answerStep++;
                    if (result > answerStep) {
                        result = answerStep;
                    }
                    return;
                }
                now.x += d[i][0];
                now.y += d[i][1];
            }
            // 起步就撞石头了 => 判断在该方向上是否只位移了一段
            if ((now.x == start.x + d[i][0] && now.y == start.y + d[i][1]) || !isLegal(now)) {
                continue;
            }
            // 石头现在已经在“墙上”了,所以这里要将这个墙打碎,并让石头后退一格
            map[now.x][now.y] = 0;
            let temp = {};
            temp.x = now.x - d[i][0];
            temp.y = now.y - d[i][1];
            dfs({ x: temp.x, y: temp.y }, ++answerStep);
            answerStep--;
            map[now.x][now.y] = 1;
        }
    }
  • 相关阅读:
    匈牙利算法(二分图匹配)
    匈牙利算法(二分图匹配)
    Redis 笔记与总结6 Redis 高级应用之 事务处理、持久化操作、pub_sub、虚拟内存
    大数据的五大误区及其破解之道
    大数据的五大误区及其破解之道
    统计之 - 协方差_数据分析师
    统计之 - 协方差_数据分析师
    数据挖掘之七种常用的方法_数据分析师
    数据挖掘之七种常用的方法_数据分析师
    方差分析一般线性模型
  • 原文地址:https://www.cnblogs.com/JobsOfferings/p/JS_poj3009.html
Copyright © 2020-2023  润新知