所有对象都可以按顺序配对吗?

时间:2013-04-19 05:26:47

标签: arrays algorithm

首先,这不是一个家庭作业或类似的东西,这是我上一个问题Candidate in finding majority element in an array中的一个暗示性问题。

n 对象O 1 ,O 2 ,...,O n < / sub>,并且有一个数组F[1...n]F[i]是Oi的数量(即有F[i] O i s,数组{{1} } {每个F[1...n]&gt; F[i]

现在使用以下规则配对对象:

如果0,O i 可以与O j 配对,
否则如果i != j,则O i 不能与O j 配对。

即,只有两种不同的物体可以相互配对。

  1. 输入数组i == j是否存在有效的配对方法?给出一个具有最佳时间复杂度的算法来判断真或假,并证明其正确性。

  2. 如果存在,则输出一个有效的配对序列。给出算法和时间/空间复杂度分析。

  3. 例如, 输入 F[1...n]

    然后至少存在一种有效的配对方法:

    2 O 1 s和2 O 2 s配对,4 O 1 s和4 O 3 配对,4 O 1 s和4 O 4 配对。

    一个有效的配对序列是:

    (1,2)(1,2)(1,3)(1,3)(1,3)(1,3)(1,4)(1,4)(1,4)(1) ,4)

2 个答案:

答案 0 :(得分:5)

检查O(n)

中是否存在解决方案

sF的总和。

  • 如果s是奇数,则没有解决方案(直观)
  • 如果存在iF[i] > s/2没有解决方案(直观)
  • 否则,存在解决方案(按照构造证明)

在O(n)

中找到解决方案
# Find s
s = 0
for i in 1..n:
    s += F[i]

# Find m such that F[m] is maximal
m = 1
for i in 1..n:
    if F[i] > F[m]:
         m = i

if s % 2 != 0 or F[m] > s/2:
    fail

a = 1
b = 1

# Pair off arbitrary objects (except those of type m) until F[m] = s/2    
while s/2 > F[m]:
    # Find a type with a non-zero frequency
    until F[a] > 0 and a != m:
        a = a + 1
    # Find another type with a non-zero frequency
    until F[b] > 0 and b != m and b != a:
        b = b + 1

    count = min(F[a], F[b], s/2 - F[m])
    pair(a, b, count)

# Pair off objects of type m with objects of different types
while F[m] > 0:
    # Find a type with a non-zero frequency
    until F[a] > 0 and a != m:
        a = a + 1
    pair(a, m, F[a])

end of algorithm

def pair(a, b, count):
    # Pairs off 'count' pairs of types a and b
    F[a] = F[a] - count
    F[b] = F[b] - count
    s = s - (2 * count)
    output "Pairing off $a and $b ($count times)"

两个while循环都是线性的。第一个while循环在每次迭代时至少增加一个ab,因为匹配count对后F[a]为零,或F[b]为零,或s/2 = F[m]并且循环终止。在访问所有元素之前,ab每次最多可增加n次。第二个while循环也是线性的,因为它在每次迭代期间将a增加至少一个。

关键不变量是
(1) F[m]F的最大元素 (2) F[m] <= s/2
我认为两者在检查时都相当明显。

对于内循环,只要s/2 > F[m]必须至少有两个其他具有非零频率的对象类型。如果只有一个,请说a,然后是 F[a] + F[m] = s
F[a] = s - F[m] > s - s/2(来自循环条件)
F[a] > s/2
F[a] > F[m]
这是一个不变的(1)

的矛盾

由于至少有两种类型具有非零频率(除m之外),循环将能够找到类型ab并将对象配对,直到{{1 }}

第二个循环是微不足道的。由于正好一半的对象属于s/2 = F[m]类型,因此m类型的每个对象都可以与不同类型的对象配对。

答案 1 :(得分:1)

这是一个建议。不过,我不确定它是否能成功应对每种可能的情况,或者它是否是最有效的算法。

n为索引总数。构造对象类型数量的最高值优先级队列,其中每个对象类型是其索引i。换句话说,创建一个优先级队列,其中队列中的排序值是F的值。将每个节点与该类型的所有对象的列表相关联。这将花费O(n log(n))时间。

对于每个对象类型,从具有最多重复项的类型开始并前进到具有最少的类型,将对象中的一个对象与该对象的“类”配对,其中每个其他类仍然具有剩余对象在其中,并从队列中的该节点中删除该对象。由于除了顶层队列之外的每个队列项目中都有一个较少的对象,因此大部分队列仍将处于优先级队列顺序;但是,顶级节点将减少n-1个项目(或者它将为空),因此堆积下来以维护队列。此外,删除没有对象的节点。使用新的最高队列值重复此过程,直到所有节点都已配对。这将花费O(n log(n) + k)时间,其中k是项目总数。假设k明显大于n,则总时间复杂度为O(k)

同样,我不太确定如果可能的话,这总能找到解决方案。我的直觉是,如果你在每次配对后重新堆积(如果有必要),你将确保如果完全配对可以找到 ,但是(1)这样效率会低得多,(2)我不确定原始算法不会成功的原因是什么,以及(3)我不完全确定每次都会有效。

至于F的哪些值没有解,显然如果存在一类具有比所有其他类合并的元素更多的对象,则不可能进行配对。除此之外......我不太确定。调查我的“改进”算法是否正确评估每个案例都会很有趣。