上一主题 下一主题
ScriptCat,新一代的脚本管理器脚本站,与全世界分享你的用户脚本油猴脚本开发指南教程目录
123下一页
返回列表 发新帖

求算法方案二维数组两点间最短路径

[复制链接]
  • TA的每日心情
    慵懒
    10 小时前
  • 签到天数: 624 天

    [LV.9]以坛为家II

    30

    主题

    532

    回帖

    1400

    积分

    荣誉开发者

    积分
    1400

    荣誉开发者新人进步奖油中2周年生态建设者新人报道挑战者 lv2油中3周年喜迎中秋

    发表于 2022-12-1 12:48:31 | 显示全部楼层 | 阅读模式
    悬赏100油猫币未解决

    本帖最后由 steven026 于 2022-12-1 12:51 编辑

    有一个大小为i×i地图以二维数组形式表示(4<i<20),

    固定有1个起点、1个终点、Math.round(i*i/2)场战斗、i个宝箱、其余均为空路
    起点以1表示、战斗以2表示,宝箱以3表示、终点以4表示、空路以0表示
    起点固定位置为[Math.floor(i/2),i-1],终点、战斗、宝箱随机分布在其余位置
    每次可以向任意方向(上下左右)移动一步,空路不消耗体力,宝箱不消耗体力,战斗消耗1点体力
    求起点至终点消耗体力最小方案
    (在消耗体力相同情况下,空路需要尽可能少,宝箱可有可无,体力消耗优先级最高)

    示例:
    image.png

    输入:

    [
    [2, 0, 0, 0, 2, 2],
    [0, 0, 2, 0, 3, 2],
    [0, 2, 4, 0, 2, 2],
    [0, 0, 2, 2, 2, 3],
    [2, 0, 0, 2, 3, 2],
    [3, 2, 0, 1, 3, 2]
    ]

    输出:
    ['左','上','左','上','左','上','上','右','上','右','右','下','下','左']

  • TA的每日心情
    开心
    5 天前
  • 签到天数: 119 天

    [LV.6]常住居民II

    29

    主题

    598

    回帖

    535

    积分

    专家

    积分
    535

    油中2周年生态建设者油中3周年挑战者 lv2

    发表于 2022-12-1 13:15:21 | 显示全部楼层
    这一个标题就让人想起lua A*算法 寻路,不过真没深入过不太懂
    入驻爱发电 让这世界充满爱 https://afdian.net/a/vpannice
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    10 小时前
  • 签到天数: 624 天

    [LV.9]以坛为家II

    30

    主题

    532

    回帖

    1400

    积分

    荣誉开发者

    积分
    1400

    荣誉开发者新人进步奖油中2周年生态建设者新人报道挑战者 lv2油中3周年喜迎中秋

    发表于 2022-12-1 14:12:37 | 显示全部楼层
    脚本体验师001 发表于 2022-12-1 13:15
    这一个标题就让人想起lua A*算法 寻路,不过真没深入过不太懂

    GGNB 我去研究研究 似乎找到了新大陆
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2023-6-12 15:07
  • 签到天数: 6 天

    [LV.2]偶尔看看I

    7

    主题

    94

    回帖

    155

    积分

    荣誉开发者

    积分
    155

    荣誉开发者油中2周年生态建设者喜迎中秋

    发表于 2022-12-1 15:23:01 | 显示全部楼层
    那自然是A-Start了
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    10 小时前
  • 签到天数: 624 天

    [LV.9]以坛为家II

    30

    主题

    532

    回帖

    1400

    积分

    荣誉开发者

    积分
    1400

    荣誉开发者新人进步奖油中2周年生态建设者新人报道挑战者 lv2油中3周年喜迎中秋

    发表于 2022-12-1 20:38:08 | 显示全部楼层
    maxzhang 发表于 2022-12-1 15:23
    那自然是A-Start了

    大致了解了下A*算法
    发现A*算法似乎不太适用于我的这种情况,需要做大改动……

    A*算法默认就起点、终点、可通过的路、不可通过的路,不存在可通过但尽量避免通过的路,且注重最短路径,
    这就导致了我无法简单地通过修改不可通过的路的代价权重来改进算法,因为改了权重就导致算法认为尽量避免通过的路是通路且较短,不会再绕路进行其他可能性计算
    回复

    使用道具 举报

  • TA的每日心情

    2022-12-1 21:24
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    2

    主题

    23

    回帖

    21

    积分

    助理工程师

    积分
    21
    发表于 2022-12-1 20:59:12 | 显示全部楼层
    实在不行就穷举吧
    回复

    使用道具 举报

  • TA的每日心情

    2022-12-1 21:24
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    2

    主题

    23

    回帖

    21

    积分

    助理工程师

    积分
    21
    发表于 2022-12-1 21:18:36 | 显示全部楼层
    本帖最后由 dannianya 于 2022-12-1 21:20 编辑

    3423255-8b6cafe0f366b594.gif 你看看这个像不像你描述的
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    10 小时前
  • 签到天数: 624 天

    [LV.9]以坛为家II

    30

    主题

    532

    回帖

    1400

    积分

    荣誉开发者

    积分
    1400

    荣誉开发者新人进步奖油中2周年生态建设者新人报道挑战者 lv2油中3周年喜迎中秋

    发表于 2022-12-1 22:33:56 | 显示全部楼层
    let m = [
        [2, 0, 0, 0, 2, 2],
        [0, 0, 2, 0, 3, 2],
        [0, 2, 4, 0, 2, 2],
        [0, 0, 2, 2, 2, 3],
        [2, 0, 0, 2, 3, 2],
        [3, 2, 0, 1, 3, 2]
    ];
    let size = m.length;
    //let start=[size-1,Math.floor(size/2)]
    //预处理地图
    let record = m.map((i, y) => i.map((m, x) => ({ x: x, y: y, value: m, cost: (m == 2) * 1, totalCost: (m == 2) * 1, parent: [] })));
    let flat = record.flat();
    //起点
    let start = flat.find(i => i.value == 1);
    //终点
    let end = flat.find(i => i.value == 4);
    
    //获取可通过的周围四个点 过滤:终点、超过边界点
    function getChild({ x, y }) {
        return [[x + 1, y], [x - 1, y], [x, y + 1], [x, y - 1]].filter(([x, y]) => { return (x < size && y < size && x >= 0 && y >= 0 && !(x == end.x && y == end.y)) }).map(([X, Y]) => flat.find(({ x, y }) => x == X && y == Y))
    }
    
    //尝试通路
    function applyChild(parent) {
        const child = getChild(parent)
        const newChild = child.filter(c => {
            const newCost = c.cost + parent.totalCost //目标消耗=子点消耗+父点总消耗
            if (c.parent.length == 0) {
                c.parent.push(parent)
                c.totalCost = newCost
            } else if (c.parent.find(i => i == parent)) {
                return false //终止走回路
            } else {
                if (c.totalCost == newCost) {
                    c.parent.push(parent)
                } else if (c.totalCost > newCost) {
                    c.totalCost = newCost
                    c.parent = [parent]
                } else {
                    return false //终止消耗过高
                }
            }
            return true
        })
        return newChild
    }
    
    let result = applyChild(start);
    
    //循环遍历通路
    while (result.length > 0) {
        result = result.map(c => applyChild(c)).flat()
    }
    //record.map(i=>i.map(i=>i.parent.length>0 && i))
    
    //获取结果
    getChild(end)

    自己强行遍历了一个,结果不及预期,暂时没发现哪里写的有问题
    预期结果是遍历完所有路径,终点右边的点totalCost应该为0,然后倒推parent路线
    实际结果是终点右边的点totalCost为2

    点评

    终于找到原因了,else if (c.parent.find(i => i == parent))需要改成else if (c.parent.find(i => i == parent) && newCost >= c.totalCost)。parent的最小totalCost亦可能会改变   发表于 2022-12-2 00:26
    不对……不是.filter的问题,修改的是对象中的属性,并没有深拷贝实际还是会影响  发表于 2022-12-1 23:46
    发现了 我在.filter里面修改当然不会生效……  发表于 2022-12-1 22:50
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    10 小时前
  • 签到天数: 624 天

    [LV.9]以坛为家II

    30

    主题

    532

    回帖

    1400

    积分

    荣誉开发者

    积分
    1400

    荣誉开发者新人进步奖油中2周年生态建设者新人报道挑战者 lv2油中3周年喜迎中秋

    发表于 2022-12-1 22:35:01 | 显示全部楼层
    dannianya 发表于 2022-12-1 21:18
    你看看这个像不像你描述的

    有点像,能发下网址我去参考一下么
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    10 小时前
  • 签到天数: 624 天

    [LV.9]以坛为家II

    30

    主题

    532

    回帖

    1400

    积分

    荣誉开发者

    积分
    1400

    荣誉开发者新人进步奖油中2周年生态建设者新人报道挑战者 lv2油中3周年喜迎中秋

    发表于 2022-12-2 01:02:00 | 显示全部楼层
    //尝试通路
    function applyChild(parent) {
        const child = getChild(parent)
        const newChild = child.filter(c => {
            const newCost = c.cost + parent.totalCost
            if (c.parent.length == 0) {
                c.parent.push(parent)
                c.totalCost = newCost
            } else if (c.parent.find(i => i == parent) && newCost >= c.totalCost) {
                return false //终止走回路
            } else {
                if (c.totalCost == newCost) {
                    c.parent.push(parent)
                } else if (c.totalCost > newCost) {
                    c.totalCost = newCost
                    c.parent = [parent]
                } else {
                    return false //终止消耗过高
                }
            }
            return true
        })
        return newChild
    }
    
    //结果逆推顺序
    function getRoute({ x, y, value, parent }, result) {
        parent = parent.filter(i => !result.find(n => n.x == i.x && n.y == i.y))//不走回路
        result.push({ x, y, value })
        if (!(start.x == x && start.y == y)) {
            parent.forEach(_parent => getRoute(_parent, [...result]))
        } else {
            routes.push(result)
        }
    }
    
    //输入数组
    let m = [
        [2, 0, 0, 0, 2, 2],
        [0, 0, 2, 0, 3, 2],
        [0, 2, 4, 0, 2, 2],
        [0, 0, 2, 2, 2, 3],
        [2, 0, 0, 2, 3, 2],
        [3, 2, 0, 1, 3, 2]
    ];
    let size = m.length;
    let record = m.map((i, y) => i.map((m, x) => ({ x: x, y: y, value: m, cost: (m == 2) * 1, totalCost: 0, parent: [] })));
    let flat = record.flat();
    let start = flat.find(i => i.value == 1);
    let end = flat.find(i => i.value == 4);
    
    //获取可通过的周围四个点
    function getChild({ x, y }) {
        return [[x + 1, y], [x - 1, y], [x, y + 1], [x, y - 1]].filter(([x, y]) => { return (x < size && y < size && x >= 0 && y >= 0 && !(x == end.x && y == end.y)) }).map(([X, Y]) => flat.find(({ x, y }) => x == X && y == Y))
    }
    
    let result = applyChild(start);
    //循环遍历通路
    while (result.length > 0) {
        result = result.map(c => applyChild(c)).flat()
    }
    //遍历结果
    result = getChild(end)
    let routes = []
    result.forEach(i => { getRoute(i, []) })
    
    //最终结果,[步数,战斗次数,宝箱数]
    routes.map(i => [i.length, i.filter(i => i.value == 2).length, i.filter(i => i.value == 3).length])
    

    最终还是一个人承担了所有😣

    回复

    使用道具 举报

    发表回复

    本版积分规则

    快速回复 返回顶部 返回列表