在二分图中,左侧有n个节点,右侧有m个节点。节点的排序从1到n和1到m。左侧的节点连接到右侧的节点。所有节点都没有连接。例如:
1 is connected to 4
2 is connected to 3
3 is connected to 2
3 is connected to 1
我想知道图中有多少交叉点(这里有5个交叉点)。 SPOJ
上存在类似的问题我想知道如何使用二进制索引树来解决这个问题,正如一些用户所提到的那样。我正在用O(n ^ 2)算法解决并获得TLE。
这不是作业。昨天我学习了BIT并且正在寻找一些问题所以我遇到了这个问题。告诉我诀窍。请不要写整个程序。
答案 0 :(得分:4)
按左节点的索引对边进行排序,然后(对于相等的左侧索引)按右节点的索引进行排序。查看右节点的索引。图中的每个交叉对应于在该排序列表中不按顺序排列的一对索引。你只需计算这种“无序”对。
按顺序将右节点的每个索引从排序列表插入二进制索引树。每次插入后,您可以在O(log(m))时间内找到树中已有多少个较大的索引。因此整个算法的时间复杂度为O(h *(log(h)+ log(m))):O(h * log(h))用于排序,O(h * log(m))用于计算数量索引反转(这里'h'是边数)。您可以使用基数排序或存储桶排序将其提高到O(h * log(m))。
<强>更新强>
正如Android Decoded所注意到的,可以使用基于Merge Sort的分而治之算法来解决反转问题的数量。查看详细解释here。这种方法的时间复杂度O(h * log(h))大于使用二进制索引树O(h * log(m))的复杂度,但对于稀疏图,边数的数量并不比数量大得多。节点,它应该更快,因为它需要更少的内存并且更易于缓存。
如果我们在合并期间消除重复条目,则合并排序方法复杂性可以提高到O(h * log(m))。为此,将“合并排序”应用于(value,numberOfInstances)对,其中相邻的相同值组合成一个具有正确“numberOfInstances”的条目。在最坏的情况下,第一次log(m)合并通过没有消除重复,这具有O(h * log(m))的复杂性;然后,当在O(h)时间内快速消除重复时,保留log(n)次传递。
二进制索引树使用详情:
实现二进制索引树,对于给定的键,可以从树中返回其索引,从最大值开始(最大的一个 - >索引0,第二个最大 - >索引1,...)。然后在将每个元素插入树之后,请求其索引 - 这将是排序列表中此元素左侧的较大值的数量。
更多细节:二进制索引树可以实现为搜索树,其每个节点由后代节点的计数器增强。不要为重复元素创建单独的节点,只需为每个元素更新后代节点计数器。当要求某个键的索引时,我们应该首先搜索一个节点,对应于树中的这个索引;然后我们应该计算当前节点的每个祖先的直接右后代的所有计数器,包括当前节点本身的右后代,但排除当前节点位于其某些祖先右侧的所有情况。
答案 1 :(得分:0)
如果我已正确理解你的问题,那么
我们知道我们可以在两组之间建立NpowerM(让这个值为X)关系 如果我们能找到没有交叉点的集合(假设我们发现它为Y)那么我们从X中减去Y,即X-Y将以数学方式回答你的问题。 为了找到Y,你在另一边对元素进行排序,在集合M上说,然后找到N和M的最长的增长子序列(&#34; http://en.wikipedia.org/wiki/Longest_increasing_subsequence")这可以在O(nm)中完成,如果你足够聪明,那么你可以在O(NlogM)......时间内完成。为了解决方案的清晰度(这里存在类似的问题&#34; http://people.csail.mit.edu/bdean/6.046/dp/"点击建筑桥梁链接)