没有寻路的A星实施

时间:2014-05-06 15:30:03

标签: artificial-intelligence a-star heuristics

我正在处理来自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

  3. 规则1)是代理人已知的,而规则2)则不是。常数j和k不为agenti

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

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

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

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

1 个答案:

答案 0 :(得分:0)

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,那么您当前的节点为71230 j = 2且 k = 5,此启发式将给出一个值2;但是,我们只需按一下按钮就可以从当前节点到达目标状态,因此在这种情况下启发式将是悲观的。这是因为每次按下按钮时,会影响两个数字,这可能比我们想象的更快地获得解决方案。为了避免这种情况,我们可以从启发式中减去一个(如果它大于一个):

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 等)。如果你被允许在你的启发式中使用 j k 的值(我假设没有,因为当你说这些是代理人不知道的时候,这就是我的解释),也许可能有一些复杂的空间,但即便如此,我也很难尝试定义它。

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