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.