类似于 TSP 的谜题的求解器,可能是用 Javascript 编写的
我创建了一个难题,它是旅行商问题的衍生问题,我称之为“Trace Perfect”。
它本质上是一个带有加权边的无向图。目标是使用最小权重在任何方向上至少遍历每条边一次(与经典 TSP 不同,传统 TSP 的目标是使用最小权重访问每个顶点)。
作为最后的扭转,一条边被分配了两个权重,每个权重对应一个遍历方向。
我每天创建一个新的拼图实例并通过 JSON 接口发布它。
现在我知道 TSP 是 NP 难的。但我的谜题通常只有少量的边和顶点。毕竟它们需要由人类来解决。因此,具有基本优化的强力可能就足够了。
我想开发一些(Javascript?)代码从服务器检索谜题,并在合理的时间内用算法解决。此外,它甚至可以将解决方案发布到服务器以在排行榜中注册。
我已经使用服务器上的后端 Java 模型在 Java 中为其编写了一个基本的强力求解器,但是代码太胖并且很快就会耗尽堆空间,正如预期的那样。
Javascript 求解器是否可行?
JSON API 很简单。您可以在以下位置找到它: http://service.traceperfect.com/api/stov?pdate =20110218 其中 pdate 是 yyyyMMdd 格式的拼图日期。
基本上一个谜题有很多条线。每条线都有两个顶点(A 和 B)。每条线有两个权重(时间A表示遍历A→B时的权重,时间B表示遍历B→A时的权重)。这应该是构建图数据结构所需的全部内容。 JSON 对象中的所有其他属性均用于视觉目的。
如果您想熟悉这个谜题,可以通过 http://www.TracePerfect.com 的 Flash 客户端来玩它/
如果有人有兴趣自己实现一个求解器,那么我将发布有关将解决方案提交到服务器的 API 的详细信息,这也非常简单。
感谢您阅读这篇较长的文章。我期待听到您对此的想法。
I have created a puzzle which is a derivative of the travelling salesman problem, which I call Trace Perfect.
It is essentially an undirected graph with weighted edges. The goal is to traverse every edge at least once in any direction using minimal weight (unlike classical TSP where the goal is to visit every vertex using minimal weight).
As a final twist, an edge is assigned two weights, one for each direction of traversal.
I create a new puzzle instance everyday and publish it through a JSON interface.
Now I know TSP is NP-hard. But my puzzles typically have only a good handful of edges and vertices. After all they need to be humanly solvable. So a brute force with basic optimization might be good enough.
I would like to develop some (Javascript?) code that retrieves the puzzle from the server, and solves with an algorithm in a reasonable amount of time. Additionally, it may even post the solution to the server to be registered in the leader board.
I have written a basic brute force solver for it in Java using my back-end Java model on the server, but the code is too fat and runs out of heap-space quick, as expected.
Is a Javascript solver possible and feasible?
The JSON API is simple. You can find it at: http://service.traceperfect.com/api/stov?pdate=20110218 where pdate is the date for the puzzle in yyyyMMdd format.
Basically a puzzle has many lines. Each line has two vertices (A and B). Each line has two weights (timeA for when traversing A -> B, and timeB for when traversing B -> A). And this should be all you need to construct a graph data structure. All other properties in the JSON objects are for visual purposes.
If you want to become familiar with the puzzle, you can play it through a flash client at http://www.TracePerfect.com/
If anyone is interested in implementing a solver for themselves, then I will post detail about the API for submitting the solution to the server, which is also very simple.
Thank you for reading this longish post. I look forward to hear your thoughts about this one.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
对于图表的大部分部分,您可以应用 http://en.wikipedia.org/wiki/Seven_Bridges_of_K %C3%B6nigsberg。
通过这种方式,您可以获得需要重复解决的行数。
一开始,您不应该从具有短顶点的节点开始,您应该在这些节点上移动两次。
如果我总结一下:
简单的递归强力求解器以及这种启发式可能是一个很好的开始方式。
或者另一种方式。
尝试找到最短的顶点,如果将它们从图重新挖掘中删除,图将只有两个奇数节点,并且将被视为可解为 Koningsberg 桥。解决方案是在这个简化的图上不拿起铅笔来求解图,一旦你点击“删除”边缘的节点,你就可以前后移动。
For most parts of graph you can apply http://en.wikipedia.org/wiki/Seven_Bridges_of_K%C3%B6nigsberg.
This way you can obtain number of lines that you should repeat in order to solve.
At beginning you should not start at nodes which has short vertices over which you should travel two times.
If I summarize:
Simple recursive brute force solver whit this heuristic might be good way to start.
Or another way.
Try to find shortest vertices that if you remove them from graph remining graph will have only two odd numbered nodes and will be considered solvable as Koningsberg bridge. Solution is solving graph without picking up pencil on this reduced graph and once you hit node whit "removed" edge you just go back and forward.
在你的java后端,你也许可以使用这个TSP代码(正在进行中),它使用Drools Planner(开源,java)。
On your java backend you might be able to use this TSP code (work in progress) which uses Drools Planner (open source, java).
如果您在 Java 中耗尽了堆空间,那么您的解决方法是错误的。
解决此类问题的标准方法是进行广度优先搜索,并过滤掉重复项。为此,您需要三个数据结构。第一个是你的图表。接下来是一个名为“状态”的待办事项队列,用于表示您尚未完成的工作。最后一个是一个哈希,它将您所处的可能“状态”映射到该对(成本,最后状态)。
在这种情况下,“状态”是对(当前节点,已遍历的边集)。
假设您拥有这些数据结构,这里是完整算法的伪代码,应该相当有效地解决这个问题。
现在
reverse(path_in_reverse)
为您提供最佳路径。请注意,
seen
的哈希值至关重要。它可以防止您陷入无限循环。看看今天的难题,这个算法最多有一百万个左右的状态需要你弄清楚。 (有 2**16 个可能的边集,以及您可能位于的 14 个可能的节点。)这很可能适合 RAM。但大多数节点只有 2 条边相连。我强烈建议折叠这些。这会将您减少到 4 个节点和 6 个边,上限为 256 个状态。 (并非所有都是可能的,请注意,现在有多个边连接两个节点。)这应该能够运行得非常快,并且几乎不使用内存。
If you are running out of heap space in Java, then you are solving it wrong.
The standard way to solve something like this is to do a breadth-first search, and filter out duplicates. For that you need three data structures. The first is your graph. The next is a queue named todo of "states" for work you have left to do. And the last is a hash that maps the possible "state" you are in to the pair (cost, last state).
In this case a "state" is the pair (current node, set of edges already traversed).
Assuming that you have those data structures, here is pseudocode for a full algorithm that should solve this problem fairly efficiently.
And now
reverse(path_in_reverse)
gives you your optimal path.Note that the hash
seen
is critical. It is what prevents you from getting into endless loops.Looking at today's puzzle, this algorithm will have a maximum of a million or so states that you need to figure out. (There are 2**16 possible sets of edges, and 14 possible nodes you could be at.) That is likely to fit into RAM. But most of your nodes only have 2 edges connected. I would strongly advise collapsing those. This will reduce you to 4 nodes and 6 edges, for an upper limit of 256 states. (Not all are possible, and note that multiple edges now connect two nodes.) This should be able to run very quickly with little use of memory.