【问题标题】:A-star implementation with no path finding没有寻路的 A-star 实现
【发布时间】:2014-05-06 15:30:03
【问题描述】:

我正在处理来自 ai 类的以下任务

我需要使用A*算法

我有一个介于 0-9 之间的 n 位显示

每个数字都用 Ci 标识,I=0...n-1

每个数字下方都有一个按钮,代理可以按下该按钮来修改其值。

每次代理按下按钮,数字都会按照 2 条规则变化

  1. Ci = (Ci+1)%10

  2. C (I+j)%n = [C (I+j)%n +k]%10

规则 1) 为代理所知,而规则 2) 不为人所知。常数 j 和 k 对 agenti 来说是未知的

我的目标是从 00...0 配置开始达到目标状态。

目标状态可以通过代理应用随机动作生成,也就是随机按下按钮,所以我确信至少有一种方法可以解决问题。

我的困难是: 如何将 n 位显示表示为节点? 如何选择正确的启发式方法? 我对这次考试感到困惑和沮丧。

(对不起英文错误,我是意大利人!)

【问题讨论】:

  • 我猜C(i+j)%n应该是C((i+j)%n),也就是你取结果索引的模n

标签: artificial-intelligence a-star heuristics


【解决方案1】:

A*算法的特点是:

  • 构成搜索树的节点。
  • “邻居”概念的定义。
  • 节点的乐观启发式定义。

搜索树中的节点

当您提出问题时,似乎搜索树的每个节点都是显示的 n 位的配置。请注意,这可以很容易地表示为大小为 n 的整数数组,其中数组的每个位置代表显示中的一个数字,而值代表显示中该数字的实际值。例如,如果显示25847 的5 位数字可以用[2, 5, 8, 4, 7] 表示。简单吧?

“邻居”概念

也就是说,你如何改变显示状态?正如您所说,您只能使用每个数字下方的 n 个按钮之一。因此,对于每种状态,如果您在搜索树上思考,您将有完全 n 个可能的“邻居”或“后代”。您将需要一个函数,为您提供按下特定按钮的节点结果(这将模拟代理按下按钮)。类似于以下内容(在 Java 中):

static int[] pressButton(int[] node, int button, int j, int k) {
    int n = node.length;
    int[] newNode = Arrays.copyOf(node, n);
    newNode[button] = (newNode[button] + 1) % 10;
    newNode[(button + j) % n] = (newNode[(button + j) % n] + k) % 10;
    return newNode;
}

现在你有了这个,你可以生成当前节点的每个子节点,如下所示:

for (int i = 0; i < node.length; i++) {
    int[] newNode = pressButton(node, i, j, k);
    // compute heuristic of the new node
    // add it to the A* priority queue
}

乐观启发式

现在您只需要一个启发式算法,它可以乐观地估计给定节点到目标的距离。一个简单的想法是假设,对于给定的节点,您必须按下按钮的次数至少与与目标不同的位数一样多;例如,如果目标是41243,当前节点是37253,则您必须至少按下按钮三次,因为与目标不同的三个数字。在 Java 中:

static int heuristic(int[] currentNode, int[] goal) {
    int h = 0;
    for (int i = 0; i < goal.length; i++) {
        if (goal[i] != currentNode[i]) {
            h = h + 1;
        }
    }
    return h;
}

但是请注意,这种启发式方法是错误的。例如,如果目标是81730,您的当前节点是71230j = 2 和 k = 5,则此启发式将给出值 2;然而,我们可以在按下按钮一的 1 步内从当前节点到达目标状态,因此在这种情况下,启发式方法将是悲观的。这是因为每次按下按钮时,都会影响两位数,这可能比我们想象的更快获得解决方案。为了避免这种情况,我们可以从启发式中减去一个(如果它大于一个):

static int heuristic(int[] currentNode, int[] goal) {
    int h = 0;
    for (int i = 0; i < goal.length; i++) {
        if (goal[i] != currentNode[i]) {
            h = h + 1;
        }
    }
    if (h > 1) {
        h = h - 1;
    }
    return h;
}

不仅可以根据与目标不同的位数,还可以根据它们的差异程度来定义更准确的启发式方法(差异越大,您需要按下按钮的次数越多);但是,我认为没有一种简单的方法可以基于此定义乐观启发式(特别要记住像 j = 0 或 j = n、负k等)。如果允许您在启发式中使用 jk 的值(我假设不是,因为当您说代理不知道这些值时,我就是这么解释的),也许有一些复杂的空间,但即使那样,我也很难定义它。

最后,考虑到问题的性质,从一个节点到另一个节点时很容易到达已经访问过的状态。如果您想将树保持为实际树(并且是有限的),而不是无限图,则必须使用一组已经访问过的节点,以避免在搜索空间中创建循环。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多