Java 递归回溯
我正在开发高级petri网编辑器/模拟器。首先,这里是一些词汇 圆圈=位置 矩形=过渡 原地整数=标记 转换中的条件=保护 而且我在通过过渡时期的守卫时也被绊倒了。Guard是一个条件,如果要执行转换,它必须为true。我知道我应该以某种方式使用回溯,但是我不知道在程序开始之前进入转换的位置的数量,所以我不能使用for循环,因为我不知道我需要多少 下面的图片说明了这个问题 所以,我想从第一位获取第一个令牌,从第二位获取第一个令牌,然后尝试通过守卫,如果通过,则保存令牌,并打破循环,如果为false,则继续使用第二位的第二个令牌..等等。。。 我终于用第一名的最后一个令牌(4)和第二名的最后一个令牌(2)通过了守卫 我会知道如何编写代码,如果我有固定数量的地方进入过渡,它会像这样Java 递归回溯,java,recursion,backtracking,Java,Recursion,Backtracking,我正在开发高级petri网编辑器/模拟器。首先,这里是一些词汇 圆圈=位置 矩形=过渡 原地整数=标记 转换中的条件=保护 而且我在通过过渡时期的守卫时也被绊倒了。Guard是一个条件,如果要执行转换,它必须为true。我知道我应该以某种方式使用回溯,但是我不知道在程序开始之前进入转换的位置的数量,所以我不能使用for循环,因为我不知道我需要多少 下面的图片说明了这个问题 所以,我想从第一位获取第一个令牌,从第二位获取第一个令牌,然后尝试通过守卫,如果通过,则保存令牌,并打破循环,如果为fal
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()方法
- 结束时
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
}