我正在编写一个模型,其中:
节点被表示为10个长度的位向量,每个长度代表一些分子,并且边缘可以将源处存在的任何分子带到目标节点。
例如
S_Node:0b0100000011 //节点上存在分子0,1,8
One_Edge:0b0000000010 //分子1正在边缘
我必须强制执行边缘的每个传出分子在某个周期返回源节点的条件。分子必须在一个循环中返回意味着在获取循环的路径期间它必须存在于evry节点和它所需的边缘上。 *允许平行边缘。
分子1采用路径S_Node - > Node_1 - > Node_2 ... - > S_Node。因此Molecule 1从边缘的S_Node开始并经过Node_1 ...并在一个周期内返回S_Node。因此,该分子满足条件。 同样,我必须检查每个边缘上的每个分子。
我正在以微不足道的方式检查每个节点可能出现的边缘,然后对于每个边缘,可能存在的位是什么,并强制每个节点在某个周期返回。
for (i = 0; i < N; i++) { // for each Node
for (j = 0; j < E; j++) { // for each Edge going out frm node i
// Lets say we have some way of finding E
if(edgeWeight & (1 << j)) { //All outgoing bits
// Enforcing that each will come back
// On some Cycle
我很容易看到我必须迭代所有节点,然后所有边出去,然后对于这些边上的每个位,必须编写代码来强制执行相同的操作。执行自己必须迭代至少没有节点#N。
有效地做到这一点有更好的方法吗?还有其他方法可以在图论中检查相同的东西吗?感谢
答案 0 :(得分:1)
节点的表示与问题无关。你有一个有向图。您希望验证每个节点和边缘是否存在包含该边的循环。并且你希望它具有合理的效率(而不是从所有边缘进行强力搜索所有可能的循环)。
这是一个观察。假设您在图表G
中找到了一个循环。考虑图表G'
,它与原始图表相同,除了周期已折叠到单个节点。 G
问题的答案与G'
问题的答案相同,因为G
中的任何一个循环都导致G'
中的一个循环(可能是自我...相交的一个可以变成2个循环),G'
中的任何循环都会导致G
中的循环(如果你碰到折叠的节点,然后按照它的循环,直到你找到退出点继续)。
所以现在问题从蛮力发现周期到崩溃周期,直到你有一个小图表,问题很容易回答。因此,对于每个节点,对于每个边,您都会启动一条路径。你的路径一直持续到你发现了一个循环。任何循环。 (不一定回到原始节点!)折叠该循环,并继续旅行,直到您必须回溯(在这种情况下您的条件不满足)或您设法循环回原始节点,折叠该循环,并移动到另一边。
如果你实现这个,你将有一个多项式算法,但不是你能做到的最好的算法。问题是创建循环崩溃的新图形是一项昂贵的操作。但有一个技巧有帮助。而不是每次找到一个循环时折叠图形,试着对它懒惰。为该周期创建一个新的“假节点”,并将该周期中的每个节点标记为该假节点。每当您看到一个到达节点的边缘时,通过这些映射进行递归搜索,找到您找到的最折叠的节点,并将您在该搜索中看到的所有内容标记为直接映射到那里。
如果你很好地实现了懒惰位,你的整体算法应该结束O(E)
,其中E
是图中边的数量。你实际上不能做得更好,因为无论你做什么,你都必须访问每一个边缘。
答案 1 :(得分:1)
你似乎每个分子有一个有向图(每位)只需要你的技巧来检查每个分子的任何非循环。
您可以采用btillys方式检查周期,另一种选择是查看strongly connected components。您基本上希望每个子图(对于给定的分子)是一个图,其中每个connected component实际上是强连接的。从与之前链接的维基百科文章中提到的强连接组件有一些很好的算法。