这是一个可以通过某种类型的暴力算法来解决的问题,但我想知道是否有一些有效的方法可以做到这一点。
假设我们有以下整数对
(1, 3), (2, 5), (4, 7), (2, 7), (10, 9)
我们想弄清楚互斥对的最大数量是多少。
互相配对,我的意思是它们没有任何配对 常用整数。
例如,我们不能同时选择(2,5),(2,7),因为两个对都包含2个。
在上述情况下,4将是一个解决方案,因为我们可以选择以下互斥对:
(1, 3), (2, 5), (4, 7), (10, 9)
因此总共有4对。
我想知道是否有有效的方法。
答案 0 :(得分:12)
您的问题相当于在图表上找到最大匹配。图形的节点是整数,您的对(a,b)是图形的边缘。匹配是一组成对的非相邻边,相当于说同一个整数不会出现在两条边上。
这个问题的多项式时间解决方案是Blossom algorithm also known as Edmond's algorithm.这里的答案细节太复杂了。
答案 1 :(得分:3)
编辑:由于我的误解,以前的方法不正确。
这是第二次尝试:
如果我们将一对中的每个数字视为图中的节点,我们可以构建一个二分图,如果有一对包含这两个节点,则每个节点之间有边。
所以,这个问题减少了,找到maximum bipartite matching,可以使用经典Ford-fulkerson algorithm来解决。
第一个错误的方法:
我们可以通过动态编程来解决这个问题。
按对象的起点(如果绘制,按其结束点)对对进行排序。
假设我们有一个函数f
,如果我们从对f(i)
开始选择,i
会返回最大对数。
如果我们选择一对i
,我们需要检查大于i
的下一个与i
不重叠的最小索引。
我们有
f(i) = max(1 + f(next index not overlap i), f (i + 1))
将f(i)
的结果存储在表中,我们可以得到 O(n ^ 2)时间复杂度的解决方案,结果将为f(0)
。< / p>
伪代码:
sort data;//Assume we have a data array to store all pairs
int[] dp;
int f(int index){
if(index == data.length)
return 0;
if(we have calculated this before)
return dp[index];
int nxt = -1;
for(int i = index + 1; i < data.length; i++){
if(data[i].start > data[index].end){
nxt = i;
break;
}
}
if(nxt == -1)
return dp[index] = max(1, f(index + 1));
return dp[index] = max(1 + f(nxt) , f(index + 1));
}
答案 2 :(得分:2)
这个问题可以用图论来重铸。图表的节点是您给出的对。如果对具有共同的数字,则连接两个节点。你的问题是找到一个最大的独立集。
最大独立集相当于找到最大集团,它既是NP完全的又是“难以近似”。但是,在这种特殊情况下,图形是一种称为“无爪”(http://en.wikipedia.org/wiki/Claw-free_graph)的特殊类型,因为如果一个节点连接到另外三个节点,那么这些节点中至少有两个必须共享一个公共数字,他们自己也是如此。
事实证明,对于无爪图的特殊情况,最大独立集问题可以在多项式时间内求解:http://en.wikipedia.org/wiki/Claw-free_graph#Independent_sets。
答案 3 :(得分:1)
修改:这不会像用户98235在评论中指出的那样奏效。我会留在这里,但万一其他人有同样的想法。
如果我能正确理解问题,我认为这会有效。
伪代码:
resultList = new List of Pair
elementSet = new Set of int
for pair in inputPairs:
if not elementSet.Contains(pair.First) and not elementSet.Contains(pair.Second):
elementSet.Add(pair.First)
elementSet.Add(pair.Second)
resultList.Add(pair)
时间复杂度为O(N)。