用Python解决图形问题
我有一种情况,我想用Python来解决这个问题,但不幸的是,我没有足够的图形知识。我发现一个库似乎非常适合这个相对简单的任务,用Python解决图形问题,python,algorithm,graph,path,networkx,Python,Algorithm,Graph,Path,Networkx,我有一种情况,我想用Python来解决这个问题,但不幸的是,我没有足够的图形知识。我发现一个库似乎非常适合这个相对简单的任务,networkx,但我在做我想要的事情时遇到了问题,这应该是相当简单的 我有一个节点列表,可以有不同的类型,和两个“类”的邻居,向上和向下。任务是查找两个目标节点之间的路径,同时考虑一些约束: 只能遍历特定类型的节点,即,如果起始节点的类型为x,则路径中的任何节点必须来自另一组路径y或z 如果节点具有类型y,则只能通过一次 如果节点的类型为z,则可以通过两次 如果访问类
networkx
,但我在做我想要的事情时遇到了问题,这应该是相当简单的
我有一个节点列表,可以有不同的类型,和两个“类”的邻居,向上和向下。任务是查找两个目标节点之间的路径,同时考虑一些约束:
- 只能遍历特定类型的节点,即,如果起始节点的类型为x,则路径中的任何节点必须来自另一组路径y或z
- 如果节点具有类型y,则只能通过一次
- 如果节点的类型为z,则可以通过两次
- 如果访问类型为z的节点,则出口必须来自不同类别的邻居,即如果从上访问,则出口必须从下
import networkx as nx
G=nx.DiGraph()
G.add_node(1, type=1)
G.add_node(2, type=2)
G.add_node(3, type=3)
G.add_edge(1,2, side="up")
G.add_edge(1,3, side="up")
G.add_edge(2,1, side="down")
G.add_edge(2,3, side="down")
for path in nx.all_simple_paths(G,1,3):
print path
输出相当不错,但我需要这些约束。那么,您是否有一些建议,我如何实现这些,或者给我一些关于理解这类问题的更多指导,或者为这类问题提出不同的方法或库?也许一个简单的基于字典的算法可以满足这个需求
谢谢 我认为最好的方法是计算源S和每个其他节点之间长度最多为k的所有有效路径,然后使用该信息计算长度最多为k+1的所有有效路径。然后重复这个过程,直到得到一个固定点,在这个固定点上没有路径被修改 实际上,这意味着您应该在每个节点上设置路径列表。在每一步中,您依次选取每个节点U,并查看在上一步中终止于U的某个相邻V的路径。如果这些路径中的任何一条可以扩展为U的新的、不同的路径,请扩展它并将其添加到U的列表中 如果在执行步骤时未找到新路径,则为终止状态。然后可以检查目标节点T处的路径列表 伪代码(采用非常松散的C#形式):
var path=graph.nodes.ToDictionary(node=>node,node=>newlist())
路径[S].Add(新列表{S})//将启动我们的普通路径。
bool notAFixedPoint=true;
while(非固定点)
{
notAFixedPoint=false//假设我们不会找到任何新路径。
foreach(图中的var节点)
{
var pathsToNode=路径[节点]
foreach(节点中的var邻居。邻居)
{
var pathsToNeighbour=路径[邻居]
//ExtendPaths是所有关于如何识别有效路径的逻辑所在。
var newPathsToNode=extendPath(pathsToNeighbour,节点)
//这里使用“除外”是为了说明目的,它实际上不起作用,
//因为大多数语言中的集合都是按引用而不是按值进行比较的。
if(newPathsToNode.Except(pathsToNode.IsNotEmpty())
{
//我们找到了一些新的路径,所以还不能终止。
notAFixedPoint=true
pathsToNode.AddMany(newPathsToNode)
}
}
}
}
返回路径[T]
在我看来,这似乎是一个优化问题——请查阅《旅行推销员》中的一个经典示例,它与您想要做的有点接近
我很幸运地使用“模拟退火”来解决优化问题,但您也可以看看“遗传算法”。如果您以不同的方式构造图形,您可能可以使用all_simple_path()函数来解决您的问题。简单路径是那些没有重复节点的路径。因此,对于您的约束,这里有一些构建图的建议,这样您就可以不经修改地运行该算法
- 只能遍历特定类型的节点,即,如果起始节点的类型为x,则路径中的任何节点必须来自另一组路径y或z
- 如果节点具有类型y,则只能通过一次
- 如果节点的类型为z,则可以通过两次
- 如果访问类型为z的节点,则出口必须来自不同类别的邻居,即如果从上访问,则出口必须从下
如果边缘按照您的建议定向,那么如果您确保到z的边缘都是同一方向的话,就可以满足这一要求-例如,向内表示向上,向外表示向下…很难理解您想要什么。你能为这个问题提供一些背景吗?不同类型的节点代表什么?您想要两个节点之间的所有路径,还是只需要最短的路径?它必须有多快?(“所有路径”可能会在打印输出时将其推到指数时间)让我们假设节点代表城市或车站,某种具有特定“类型”的位置,表示
var paths = graph.nodes.ToDictionary(node => node, node => new List<List<node>>())
paths[S].Add(new List<node> {S}) // The trivial path that'll start us off.
bool notAFixedPoint = true;
while (notAFixedPoint)
{
notAFixedPoint = false // Assume we're not gonna find any new paths.
foreach (var node in graph)
{
var pathsToNode = paths[node]
foreach (var neighbour in node.Neighbours)
{
var pathsToNeighbour = paths[neighbour]
// ExtendPaths is where all the logic about how to recognise a valid path goes.
var newPathsToNode = ExtendPaths(pathsToNeighbour, node)
// The use of "Except" here is for expository purposes. It wouldn't actually work,
// because collections in most languages are compared by reference rather than by value.
if (newPathsToNode.Except(pathsToNode).IsNotEmpty())
{
// We've found some new paths, so we can't terminate yet.
notAFixedPoint = true
pathsToNode.AddMany(newPathsToNode)
}
}
}
}
return paths[T]