Faça conjuntos disjuntos sem esvaziá-los

8

Suponha que você tenha um conjunto de conjuntos de números inteiros. É possível que alguns dos conjuntos se sobreponham (isto é, compartilhando elementos). Você pode se livrar das sobreposições excluindo elementos dos conjuntos, mas alguns deles podem acabar vazios; isso seria uma vergonha. Podemos tornar todos os conjuntos disjuntos sem esvaziar nenhum deles?

Observe que, nessa situação, nunca há motivo para deixar vários elementos em um conjunto; portanto, esse problema sempre pode ser resolvido reduzindo-se cada conjunto a apenas um elemento. Essa é a versão do problema que estamos resolvendo aqui.

A tarefa

Escreva um programa ou função, da seguinte maneira:

Entrada : uma lista de conjuntos de números inteiros.

Saída : uma lista de números inteiros, do mesmo tamanho que a entrada, para a qual:

  • Todos os números inteiros na saída são distintos; e
  • Cada número inteiro na saída é um elemento do conjunto correspondente da entrada.

Esclarecimentos

  • Você pode representar um conjunto como uma lista, se desejar (ou o que for apropriado para o seu idioma), desconsiderando a ordem dos elementos.
  • Você não precisa lidar com o caso em que não existe solução (ou seja, sempre haverá pelo menos uma solução).
  • Pode haver mais de uma solução. Seu algoritmo sempre deve produzir uma solução válida, mas pode ser não determinístico (ou seja, tudo bem se ele escolher uma solução válida diferente toda vez que for executado).
  • O número de números inteiros distintos que aparecem na entrada, n , será igual ao número de conjuntos na entrada e, por simplicidade, serão os números inteiros de 1 a n, inclusive (já que seus valores reais não importam). Depende de você se você deseja explorar esse fato ou não.

Casos de teste

[{1,2},{1,3},{1,4},{3,4}] -> [2,3,1,4] or [2,1,4,3]
[{1,3},{1,2,4},{2,3},{3},{2,3,4,5}] -> [1,4,2,3,5]
[{1,3,4},{2,3,5},{1,2},{4,5},{4,5}] -> [1,3,2,4,5] or [3,2,1,4,5] or [1,3,2,5,4] or [3,2,1,5,4]

Condição de vitória

Um programa requer uma complexidade de tempo ideal para vencer, ou seja, se um algoritmo com uma complexidade de tempo melhor for encontrado, desqualifica todas as entradas mais lentas. (Você pode supor que os componentes internos do seu idioma sejam executados o mais rápido possível, por exemplo, você pode assumir que um componente ordenado seja executado no tempo O (n log n). Da mesma forma, suponha que todos os números inteiros de tamanho comparável a n possam ser adicionados, multiplicados, etc. em tempo constante.)

Como é provável que seja fácil obter uma complexidade de tempo ideal na maioria dos idiomas, o vencedor será, portanto, o programa mais curto entre aqueles com complexidade de tempo vencedora, medidos em bytes.

Fred Russell
fonte
Se não faz sentido, por que é que eles entenderam isso aqui dreamincode.net/forums/topic/…
fred russell
@ fredrussell talvez, apenas talvez, seja sobre como você explica, e não sobre, por exemplo, a notação na imagem?
N
7
@fredrussell, sua explicação para o "desafio" não é clara e não está formatada. Neste site, você normalmente encontrará perguntas ordenadas e formatadas adequadamente, por exemplo, seguindo um layout como "Entrada; Saída; Regras; Casos de teste", mas você não está fornecendo nada disso. Além disso, você não possui um critério de vitória que possa determinar um vencedor. E depois do seu insulto, acho que ninguém está disposto a resolver a questão agora. Mesmo no SO, você deve sempre ter em mente que as pessoas que atendem estão fazendo isso em seu tempo livre, para que não seja rude assim.
Luca H #
1
O código mais rápido do @Arnauld implicaria que, se escrevermos algoritmos O (n), mas o seu for 100 vezes mais rápido, você ganhará. Se exigirmos apenas uma complexidade de tempo ideal, tudo bem se meu código for 100 vezes mais lento, desde que seja um byte menor. Mas esse desafio pode ser considerado o algoritmo mais rápido .
Misha Lavrov
2
Esse é exatamente o problema de encontrar uma correspondência completa em um gráfico bipartido. As complexidades de tempo dos algoritmos mais conhecidos dependem de quão grandes os conjuntos são comparados ao número de conjuntos. Desafio relacionado.
Zgarb

Respostas:

2

Geléia , 8 bytes

Œp⁼Q$ÐfḢ

Experimente online!

Explicação

Œp⁼Q$ÐfḢ  Main Link
Œp        Cartesian Product of the elements; all possible lists
     Ðf   Filter; keep elements that are
  ⁼Q$     Equal to themselves uniquified
      Ḣ   Take the first one

Extremamente ineficiente. Assintótico de ϴ(n^(n+1))acordo com Misha Lavrov; Eu acho que está certo.

HyperNeutrino
fonte
Penso que este é pelo menos Ω (n ^ n): o tamanho máximo possível do produto cartesiano.
Misha Lavrov
Mais precisamente, ϴ (n ^ (n + 1)), uma vez que a verificação "igual a si mesma unificada" deve ser ϴ (n) tempo.
Misha Lavrov
@MishaLavrov Ah tudo bem, obrigado.
HyperNeutrino
A uniquefunção @HyperNeutrino na verificação de uso de geléia Jelly O(n)( x in s), cada uma deve levar de O(n)acordo com esta página , portanto, Qdeve levar no O(n^2)pior caso / complexidade média de tempo do caso. Portanto, o algoritmo é O(n^(n+2)). (original pode ser O(n)no caso de todos os elementos são iguais, em que cada cheque de contenção é executado em O(1)) --- Em uma nota não relacionada, é possível implementar uniqueno O(n)usando Python incorporado setestrutura de dados que é mistura-conjunto. Enfim, o Jelly não foi projetado para ser eficiente.
user202729
2

Wolfram Language (Mathematica) , 87 bytes e ϴ (n 3 )

-Range[n=Length@#]/.Rule@@@FindIndependentEdgeSet[Join@@Table[-i->j,{i,n},{j,#[[i]]}]]&

Experimente online!

Constrói um gráfico bipartido cujos vértices de um lado são os conjuntos (indexados por -1,-2,...,-n) e cujos vértices do outro lado são os elementos 1,2,...,n, com uma aresta de -iaté jquando jcontida no i-ésimo conjunto. Encontra uma correspondência perfeita neste gráfico usando um built-in. Em seguida, lista os elementos correspondentes -1,-2,...,-nnessa ordem na correspondência perfeita.

O Mathematica FindIndependentEdgeSeté o gargalo aqui; tudo o mais exige operações O (n 2 ). O Mathematica provavelmente usa o algoritmo húngaro e, portanto, assumirei que ele é executado em ϴ (n 3 ) , embora seja possível que o Mathematica tenha uma implementação ingênua com complexidade O (n 4 ).

Misha Lavrov
fonte
Bem ... O Mathematica é ruim em complexidade restrita , não pela primeira vez.
user202729
2

Haskell , 48 bytes

-1 byte graças a nimi.

import Data.List
head.filter((==)<*>nub).mapM id

Experimente online!

totalmente humano
fonte
2
mapM idem vez desequence
nimi
1

Mathematica 39 Bytes

Last@Union[DeleteDuplicates/@Tuples@#]&

Na questão da complexidade, acho que é muito dependente do tamanho de cada sub-lista, bem como uma medida de quão disjuntos são os sublistas.

Então, acho que esse algoritmo é O (n Log n + n ^ 2 Log m), em que m é aproximadamente o comprimento médio de cada sub-lista.

Algo assim teria complexidade O (a ^ n) onde a> 1 é uma medida da sobreposição em sublistas:

(For[x={1,1},!DuplicateFreeQ@x,x=RandomChoice/@#];x)&

Difícil dizer qual é realmente mais rápido sem conhecer as propriedades de possíveis entradas.

Kelly Lowder
fonte
2
A DeleteDuplicates /@ Tuples@#etapa leva tempo ϴ (n ^ (n + 1)) pelos mesmos argumentos das outras soluções. Em seguida, Unionhá uma lista de comprimento n ^ n para classificar, o que leva tempo O (n ^ (n + 1) log (n)) - mas talvez seja mais rápido, pois no máximo 2 ^ nn! elementos nessa lista são distintos. De qualquer forma, a complexidade é ϴ (n ^ (n + 1)) até um fator de log (n).
Misha Lavrov
Penso que este problema requer uma definição multivariada de grande notação O para ter algum significado prático. Obviamente, o comprimento das sublistas é incrivelmente importante.
quer
1
Minha interpretação da afirmação do problema é que apenas a dependência de n (o número de sublistas) é importante, e assumimos o pior caso sobre o tamanho das sublistas. De qualquer forma, mesmo que cada sub-lista tenha tamanho 2, Tuples@#tamanho 2 ^ n, portanto, sua primeira estimativa assintótica não pode ser verdadeira.
Misha Lavrov
Hã? Por que o BigO multivariado é problemático? É feito o tempo todo.
user202729
1

05AB1E , 13 bytes, O (n! * N)

āœʒ‚øε`QO}P}н

Experimente online! Explicação:

ā               Make a range 1..n
 œ              Generate all permutations
  ʒ        }    Filter
   ‚ø           Zip with input
     ε   }      Loop over sets
      `QO       Check each element for membership
          P     All sets must match
            н   Take the first result
Neil
fonte
1

Casca , 5 bytes

►oLuΠ

Experimente online!

Explicação

Acabei de ver o que é complexidade: como costuma acontecer na solução das linguagens de golfe, elas não são muito eficientes - essa possui complexidade O (n · nⁿ).

►(Lu)Π  -- input as a list of lists, for example: [[1,2],[1,3],[1,4],[3,4]]
     Π  -- cartesian product: [[1,1,1,3],...,[2,3,4,4]]
►(  )   -- maximum by the following function (eg. on [1,1,1,3]):
   u    --   deduplicate: [1,3]
  L     --   length: 2
ბიმო
fonte
0

Pitão , 9 bytes (ϴ (n n + 1 ))

Como isso funciona exatamente como a solução Jelly, provavelmente tem a mesma complexidade.

h{I#.nM*F

Experimente aqui!

Quão?

h {I # .nM * F | Programa completo.

       * F Dobre o produto cartesiano.
    .nM | Achate cada um.
   # | Mantenha aqueles:
 {I que são invariantes sobre a remoção de elementos duplicados.
h Pegue o primeiro elemento.
Mr. Xcoder
fonte
0

JavaScript (ES6), 74 73 bytes

1 byte salvo, graças a @Neil.

f=([a,...A],s=[],S)=>a?a.map(c=>s.includes(c)||(S=S||f(A,[...s,c])))&&S:s

Iera repetidamente pela matriz, procurando uma solução.

Ungolfed:

f=(
   [a, ...A],                        //a is the first array, A is the rest
   s = [],                           //s is the current trial solution
   S                                 //S holds the solution (if one exists) at this branch
  )=>
     a ? a.map(                      //if we're not done, iterate through a
           c => s.includes(c) ||     //  if this element already exists, short-circuit
                (S = S ||            //  else if S has a solution, keep it
                 f(A, [...s, c])     //  else look for a solution down this branch
                )
         ) && S                      //return S

Casos de teste:

Rick Hitchcock
fonte
Por que não a?a.map(... )&&S:s?
611 Neil
@ Neil, porque Duh. Obrigado!
Rick Hitchcock
0

Python3, 93 84 bytes

-9 bytes graças a caird coinheringaahing

lambda I:next(filter(lambda x:len(x)==len({*x}),product(*I)))
from itertools import*

Experimente online!

Setop
fonte
1
84 bytes
caird coinheringaahing