Java 递归回溯

Java 递归回溯,java,recursion,backtracking,Java,Recursion,Backtracking,我正在开发高级petri网编辑器/模拟器。首先,这里是一些词汇 圆圈=位置 矩形=过渡 原地整数=标记 转换中的条件=保护 而且我在通过过渡时期的守卫时也被绊倒了。Guard是一个条件,如果要执行转换,它必须为true。我知道我应该以某种方式使用回溯,但是我不知道在程序开始之前进入转换的位置的数量,所以我不能使用for循环,因为我不知道我需要多少 下面的图片说明了这个问题 所以,我想从第一位获取第一个令牌,从第二位获取第一个令牌,然后尝试通过守卫,如果通过,则保存令牌,并打破循环,如果为fal

我正在开发高级petri网编辑器/模拟器。首先,这里是一些词汇

圆圈=位置

矩形=过渡

原地整数=标记

转换中的条件=保护

而且我在通过过渡时期的守卫时也被绊倒了。Guard是一个条件,如果要执行转换,它必须为true。我知道我应该以某种方式使用回溯,但是我不知道在程序开始之前进入转换的位置的数量,所以我不能使用for循环,因为我不知道我需要多少

下面的图片说明了这个问题

所以,我想从第一位获取第一个令牌,从第二位获取第一个令牌,然后尝试通过守卫,如果通过,则保存令牌,并打破循环,如果为false,则继续使用第二位的第二个令牌..等等。。。 我终于用第一名的最后一个令牌(4)和第二名的最后一个令牌(2)通过了守卫

我会知道如何编写代码,如果我有固定数量的地方进入过渡,它会像这样

for token in place 1
     for token in place 2
        try pass guard
        if (passed) 
            save tokens
             break;
但正如我之前所说,我没有固定数量的地方进入过渡期,所以我不能使用这种方法。 所以,基本上,我需要尝试令牌的组合,并尝试通过防护-直到我通过防护,或者直到我尝试了所有组合。 你有什么想法吗?伪代码就足够了。 顺便说一下,我使用这些数据结构

位置列表-普通java列表,列表位置=新ArrayList()

每个地方都有自己的标记列表,list tokens=new ArrayList()

///编辑: 卫兵有以下格式:

op1 rel op2, 其中op1是变量,op2是常量或变量,rel是关系(,=,…) 与逻辑运算符和连接的guard中可能存在多个条件-例如: op1 rel op2和&op3 rel op4

----编辑:

所以我试着实现Rushil算法,但它有很多缺陷,所以我发布了SSCCE,以便您可以尝试一下,也许可以帮上一点忙

首先,创建Place类:

public class Place {
public List<Integer> tokens ;

//constructor
public Place() {

  this.tokens = new ArrayList<Integer>();  
}

}
所以,你看,有些组合是正确的,比如1,3,6和1,3,7。。。但是4,5,8是绝对的胡说八道,因为4一开始就不是偶数。。。还有一些组合是完全缺失的,比如2,4,6等等。。。有人知道为什么会这样吗


编辑:现在它工作得很好。

像这样的东西怎么样:

method getPassed(places, tokens):
    if places are empty:
        try pass guard
            if (passed) 
                save tokens
                return true
            else return false
    else:
        for token in places[0]:
            if getPassed(places[1:].clone(), tokens.clone().append(token)):
                break
以call getPassed(places,[])开始,其中places是一个位置列表,[]是空列表。请注意,您需要始终复制列表,以免最终将其弄乱

最后,不需要配对。如果您保留在开始时传递到算法中的原始位置列表,您就知道标记[i]是为原始位置[i]选择的

但是如果您愿意,您可以保留tokenPlaces对,而不是token,因此如下所示:

method getPassed(places, tokenPlacePairs):
    if places are empty:
        try pass guard
            if (passed) 
                save tokens
                return true
            else return false
    else:
        for token in places[0]:
            if getPassed(places[1:].clone(), tokens.clone().append((token, places[0]))):
                break
编辑:仍然有些混乱,希望这能让事情变得清楚。我试图递归地生成for循环。因此,如果places只有2个元素,您将得到您建议的结果:

for token in place 1
     for token in place 2
        try pass guard
        if (passed) 
            save tokens
             break;
因此,它所做的是从列表中占据第一位,并创建“for token in place 1”循环。然后,它从位置列表中剪切该位置的一部分,并将当前标记添加到标记列表中。这个递归调用现在执行“for token in place 2”循环。等等每次递归调用我们都会将位置数减少1,并为循环创建1。因此,在places列表为空之后,我们有n个嵌套循环,其中n是位置的数量,据我所知,这就是您所寻找的

您可以通过以下方式启动该方法:

originalPlaces = places.clone()
getPassed(places, [])

通过这种方式,您可以保持原始位置不变,并且当您在递归中到达基本情况时,即当您试图确定通过保护时,您可以将令牌[i]分配给原始位置[i]。因此,您并不真正需要这些对。

递归方法将使其变得简单:

boolean Func( ListOfPlaces places, int index ) // index points to the current "place"
{

 If index >= NumberOfTokens (if index points to a place, which doesn't exist)
   {
   // if control reaches here, it means that we've recursed through a particular combination ( consisting of exactly 1 token from each place ), and there are no more "places" left. You have all the tokens you need, in your stack.

   try pass guard; if passed, save tokens and return true

   else, remove token last added to the stack & and return false
   }

 place p = places[index] 

 foreach token in p
 {
   add token to your stack
   if ( Func( places, index+1 ) ) return true
 }

 remove last token added to the stack
 return false
}
最初使用index=0调用函数


希望这有帮助。:-)

您可以自己进行循环管理。我的意思是:您需要一个类来描述每个地方的迭代状态。让我们称之为地方之州。它将由两个值组成:当前索引和最大索引

接下来,您将有一个名为iteration_admin的类,它由一个state_of_place数组和一个称为iteration_in_progress的布尔值组成。创建时,布尔值设置为TRUE。您将创建尽可能多的位置对象的状态。当前的_索引将是0,max_索引将是该位置上的令牌数

迭代_admin类需要一个方法来表示循环变量的增量。我们称之为increment()。如果当前索引仍低于最大索引,此方法将增加具有最高索引的\u位置元素的状态\u的当前\u索引。 如果当前索引等于最大索引,则当前索引将设置为0,并且具有下一个较低索引的位置的状态的当前索引需要增加。 如果该索引已达到其max_索引,则该索引将设置为0,下一个较低的索引将递增,依此类推。 当然,唯一的例外是位置[0]的状态。如果当前索引中的元素将超过其最大索引,则正在进行的布尔迭代将设置为FALSE。这意味着,所有令牌的组合都已被使用

现在,你测试警卫的代码会

  • 初始化类型为iteration\u admin的对象
  • 而iteration_admin.iteration_in_progress是真的
  • 通过使用\u place元素的状态\u中的当前\u索引值,为pass()方法构建参数列表
  • 呼叫通行证()
  • 如果未传递,则调用迭代\u admin.increment()方法
  • 结束时
编辑: 试图用伪代码来表达这个想法。我担心它看起来更像是Java和PL/SQL的混合,而不是
originalPlaces = places.clone()
getPassed(places, [])
boolean Func( ListOfPlaces places, int index ) // index points to the current "place"
{

 If index >= NumberOfTokens (if index points to a place, which doesn't exist)
   {
   // if control reaches here, it means that we've recursed through a particular combination ( consisting of exactly 1 token from each place ), and there are no more "places" left. You have all the tokens you need, in your stack.

   try pass guard; if passed, save tokens and return true

   else, remove token last added to the stack & and return false
   }

 place p = places[index] 

 foreach token in p
 {
   add token to your stack
   if ( Func( places, index+1 ) ) return true
 }

 remove last token added to the stack
 return false
}
   // iteration state for one place
class state_of_a_place 
{
   integer current_index;
   integer max_index;
}

   // iteration administration for one transition
class iteration_admin
{
   boolean iteration_in_progress
   state_of_a_place[] state_of_places

   procedure increment
   {
         // move index through tokens
      FOR i IN state_of_places.count-1 .. 0 LOOP     
         IF state_of_places[i].current_index < state_of_places[i].max_index THEN
            state_of_places[i].current_index += 1
            return
         ELSE
            state_of_places[i].current_index = 0
            IF i = 0 THEN
               iteration_in_progress = FALSE
            END IF
         END IF
      END FOR         
   }
}

handle_transition (list_of_places)
{
      // initialize an object of type iteration_admin
   iteration_admin ia
   ia.iteration_in_progress = TRUE
   FOR i IN 0..list_of_places.count LOOP
      ia.state_of_places[i].current_index = 0
      ia.state_of_places[i].max_index = list_of_places[i].number_of_tokens
   END FOR

   WHILE ia.iteration_in_progress LOOP
         // build the argument list for the pass() method 
      token[] arguments
      FOR i IN 0..list_of_places.count LOOP
         arguments[i] = list_of_places[i].token[ia.state_of_places[i].current_index]
      END FOR

         // try to pass the guard
      call pass(arguments)
      IF (passed)
         // do whatever you need to do here
      ELSE
         ia.increment()
      END IF         
   END WHILE
}
public boolean isEnabled() {
    // check for some special input/output conditions (no arcs, etc.)
    // return false if invalid

    // check to see if all input arcs are enabled
    for (Arc inputArc : inputArcs)
        if (!inputArc.isEnabled())
            return false;
    // should check if there's a guard first...
    return guard.evaluate();  // do the selection of tokens from inputs here and evaluate
}