这是一个单路径状态机矩阵的简单案例。
很抱歉伪代码采用C#风格,但使用对象更容易表达思想。
首先,构建一个转换矩阵。
请阅读我对转换矩阵的描述(不要关心FSM答案,只需了解转换矩阵的说明),链接为:
如何测试大型状态机?。
然而,您所描述的限制使情况变得简单,并且成为了一个简单的单路径状态机。这是可能的最简单的状态机,具有完整的覆盖范围。
对于5个机场的简单情况,
垂直节点=源/入口点,
水平节点=目标/出口点。
A1 A2 A3 A4 A5
A1 x
A2 x
A3 x
A4 x
A5 x
请注意,对于每一行和每一列,都不应该有超过一个转换。
要获取机器的路径,您需要将矩阵排序为
A1 A2 A3 A4 A5
A2 x
A1 x
A3 x
A4 x
A5 x
或者将其排序为一个对角方阵 - 有序对的特征向量。
A1 A2 A3 A4 A5
A2 x
A5 x
A1 x
A3 x
A4 x
有序对列表为:
a2:a1,a5:a2,a1:a3,a3:a4,a4:a5。
或者更正式地表示为:
<a2,a1>, <a5,a2>, <a1,a3>, <a3,a4>, <a4,a5>.
嗯...有序对?在Lisp中闻到了递归的味道?
<a2,<a1,<a3,<a4,a5>>>>
这个机器有两种模式:
- 旅行计划 - 你不知道有多少个机场,需要一个通用的旅行计划来规划未知数量的机场。
- 旅行重建 - 你拥有一次过去旅行的所有收费站票据,但它们都堆在你的手套箱/行李袋里。
我猜你的问题是关于旅行重建的。所以,你可以从那堆票中随机挑选一张接一张地查看。
我们假设票堆的大小是无限的。
tak mnx cda
bom 0
daj 0
phi 0
当数值为0时,表示未排序的票。我们将未排序的票定义为其目的地与另一张票的出发地不匹配的票。
接下来的票发现mnx(dst) = kul(src)匹配。
tak mnx cda kul
bom 0
daj 1
phi 0
mnx 0
当您选择下一个机票时,有可能连接两个连续的机场。如果发生这种情况,您将从这两个节点创建一个群集节点:
<bom,tak>, <daj,<mnx,kul>>
矩阵被简化,
tak cda kul
bom 0
daj L1
phi 0
在哪里
L1 = <daj,<mnx,kul>>
这是主列表的子列表。
继续挑选下一个随机票。
tak cda kul svn xml phi
bom 0
daj L1
phi 0
olm 0
jdk 0
klm 0
将现有的目标地址匹配到新的源地址
或将现有的源地址匹配到新的目标地址:
tak cda kul svn xml
bom 0
daj L1
olm 0
jdk 0
klm L2
<bom,tak>, <daj,<mnx,kul>>, <<klm,phi>, cda>
上述拓扑练习仅用于视觉理解。以下是算法解决方案。
概念是将有序对聚类成子列表,以减轻我们将用于存储票据的哈希结构的负担。逐渐地,会有越来越多的伪票(由匹配的票合并而成),每个伪票都包含一个不断增长的有序目的地子列表。最后,将剩下一个单一的伪票,其中包含其子列表中完整的行程向量。
正如您所看到的,这可能最好使用Lisp完成。
然而,作为链表和映射的练习...
创建以下结构:
class Ticket:MapEntry<src, Vector<dst> >{
src, dst
Vector<dst> dstVec;
Ticket(src,dst){
this.src=src;
this.dst=dst;
this.dstVec.append(dst);
}
}
class TicketHash<x>{
x -> TicketMapEntry;
void add(Ticket t){
super.put(t.x, t);
}
}
因此,有效地说,
TicketHash<src>{
src -> TicketMapEntry;
void add(Ticket t){
super.put(t.src, t);
}
}
TicketHash<dst>{
dst -> TicketMapEntry;
void add(Ticket t){
super.put(t.dst, t);
}
}
TicketHash<dst> mapbyDst = hash of map entries(dst->Ticket), key=dst
TicketHash<src> mapbySrc = hash of map entries(src->Ticket), key=src
当从堆中随机选取一张票时,
void pickTicket(Ticket t){
Ticket zt = dstExists(t);
if(zt!=null)
t = zt;
if (srcExists(t)!=null) return;
else {
mapbyDst.add(t);
mapbySrc.add(t);
}
}
检查目标是否存在:
Ticket dstExists(Ticket t){
Ticket zt = mapbyDst.getEntry(t.src);
if (zt==null) return false;
Ticket xt = mapbySrc.getEntry(t.src);
xt.srcVec.join(t.srcVec);
mapbyDst.remove(zt);
mapbyDst.add(zt);
return zt;
}
Ticket srcExists(Ticket t){
Ticket zt = mapbySrc.getEntry(t.dst);
if (zt==null) return false;
Ticket xt = mapbyDst.getEntry(t.dst);
xt.srcVec.join(t.srcVec);
mapbySrc.remove(zt);
mapbySrc.add(zt);
return zt;
}
检查是否存在src:
Ticket srcExists(Ticket t){
Ticket zt = mapbySrc.getEntry(t.dst);
if (zt == null) return null;
mapbySrc.remove(zt);
mapbySrc.getEntry(zt);
zt.srcVec.append(t.srcVec);
return zt;
}
我感觉以上内容有很多错别字,但概念应该是正确的。如果发现任何错误,请请求帮助进行更正。