Digamos que todos os seus conjuntos sejam subconjuntos finitos de N. DeixeiS⊆P(N) denotar seu conjunto de conjuntos.
Você quer duas operações:
O1(S,s′): Para qualquer s′⊆N, adicionar s′ para S
O2(S,s′): Para qualquer s′⊆N, existe algum s∈S de modo a s⊆s′?
Aqui estão algumas idéias para acelerar as coisas:
Você vai testar se um conjunto se um subconjunto de outro muito, então você provavelmente deve manter o tamanho |s| de cada conjunto s disponível em O(1) para que quando você precisar testar se s⊆s′, você começa verificando se |s|≤|s′|e se não, você pode retornar falso imediatamente. E você realmente tem|s|≤|s′|, basta executar o teste lento normal.
Observe que se você tiver s1∈S e s2∈S, de modo a s1⊆s2, então se s2⊆s′, você também tem s1⊆s′. Então você não precisa manters2 no S para O2. Então você pode representarS por um conjunto de conjuntos para que s∈S e s⊊s′ implica s′∉S. Em outras palavras, você só precisa acompanhar os conjuntos emSque são mínimos para inclusão. Isso pode ser implementado com bastante eficiência: Ao adicionar um conjuntos′, para todos os conjuntos s∈S de modo a |s|≤|s′| (ordenado pelo aumento do cardeal), se s⊆s′, então não adicione s′ porque não será mínimo (ou já está em S) Caso contrário, adiciones′ e depois entre conjuntos s∈S de modo a |s′|<|s|, remova-os para que s′⊆s (porque eles não são mais mínimos).
Mantenha um conjunto t isso é igual à união de todos os conjuntos S. Então, ao invés de correrO2(S,s′), você pode correr O2(S,s′∩t) em vez disso (porque se por algum s∈S, s⊆s′então desde s⊆t, s⊆s′∩t e se s⊆s′∩t, então s⊆s′∩t⊆s′)
Com essas idéias em mente, eu representaria S por um dictionnary (implementado como uma lista duplamente ligada de pares (key,value) com as teclas em ordem crescente) d de modo a d(k) é uma lista duplamente vinculada que contém exatamente o mínimo (para inclusão) de conjuntos S do cardeal k.
O1(S,s')
if O2(S,s')
return
if d(k) doesn't exist
d(k) := new_doubly_linked_list()
add(d(k),s')
S.t := union(S.t, s')
for each key k of d so that |s'|+1 <= k
for s in d(k)
if subset(s', s)
remove s
_O2(S,s')
for each key k of d so that k <= |s'|
for s in d(k)
if subset(s,s')
return true
return false
O2(S,s')
return _O2(S,inter(S.t,s'))
(Observe que, embora eu não tenha feito isso explicitamente no código de O1
, você pode fazer uma única travessia da lista duplamente vinculada que representa d
)
Não acho que isso melhore muito no pior dos casos, mas, em média, deveria.