Primeiro, algumas definições:
- Dado
n
ek
, considere a lista classificada de multisets , onde, para cada multiset, escolhemosk
números{0, 1, ..., n-1}
com repetições.
Por exemplo, para n=5
e k=3
, temos:
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 0, 4), (0, 1, 1), ( 0, 1, 2), (0, 1, 3), (0, 1, 4), (0, 2, 2), (0, 2, 3), (0, 2, 4), (0, 3, 3), (0, 3, 4), (0, 4, 4), (1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 1, 4), (1, 2, 2), (1, 2, 3), (1, 2, 4), (1, 3, 3), (1, 3, 4), (1, 4, 4) , (2, 2, 2), (2, 2, 3), (2, 2, 4), (2, 3, 3), (2, 3, 4), (2, 4, 4), ( 3, 3, 3), (3, 3, 4), (3, 4, 4), (4, 4, 4)]
- Uma parte é uma lista de multisets com a propriedade de pelo menos o tamanho da interseção de todos os multisets da peça
k-1
. Ou seja, pegamos todos os multisets e os cruzamos (usando a interseção multiset) de uma só vez. Como exemplos,[(1, 2, 2), (1, 2, 3), (1, 2, 4)]
é uma parte, pois sua interseção é do tamanho 2, mas[(1, 1, 3),(1, 2, 3),(1, 2, 4)]
não é, porque sua interseção é do tamanho 1.
Tarefa
Seu código deve receber dois argumentos n
e k
. Ele deve avidamente percorrer esses multisets na ordem classificada e exibir as partes da lista. Para o caso n=5, k=3
, o particionamento correto é:
(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 0, 4)
(0, 1, 1), (0, 1, 2), (0, 1, 3), (0, 1, 4)
(0, 2, 2), (0, 2, 3), (0, 2, 4)
(0, 3, 3), (0, 3, 4)
(0, 4, 4)
(1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 1, 4)
(1, 2, 2), (1, 2, 3), (1, 2, 4)
(1, 3, 3), (1, 3, 4)
(1, 4, 4)
(2, 2, 2), (2, 2, 3), (2, 2, 4)
(2, 3, 3), (2, 3, 4)
(2, 4, 4)
(3, 3, 3), (3, 3, 4)
(3, 4, 4), (4, 4, 4)
Aqui está outro exemplo para n = 4, k = 4
.
(0, 0, 0, 0), (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)
(0, 0, 1, 1), (0, 0, 1, 2), (0, 0, 1, 3)
(0, 0, 2, 2), (0, 0, 2, 3)
(0, 0, 3, 3)
(0, 1, 1, 1), (0, 1, 1, 2), (0, 1, 1, 3)
(0, 1, 2, 2), (0, 1, 2, 3)
(0, 1, 3, 3)
(0, 2, 2, 2), (0, 2, 2, 3)
(0, 2, 3, 3), (0, 3, 3, 3)
(1, 1, 1, 1), (1, 1, 1, 2), (1, 1, 1, 3)
(1, 1, 2, 2), (1, 1, 2, 3)
(1, 1, 3, 3)
(1, 2, 2, 2), (1, 2, 2, 3)
(1, 2, 3, 3), (1, 3, 3, 3)
(2, 2, 2, 2), (2, 2, 2, 3)
(2, 2, 3, 3), (2, 3, 3, 3)
(3, 3, 3, 3)
Esclarecimento sobre o que significa ganancioso: Para cada multiset, por sua vez, procuramos ver se ele pode ser adicionado à peça existente. Se pudermos adicioná-lo. Se não pudermos, começamos uma nova peça. Observamos os multisets na ordem classificada, como no exemplo acima.
Resultado
Você pode gerar o particionamento em qualquer formato que desejar. No entanto, multisets devem ser escritos horizontalmente em uma linha. Esse é um conjunto múltiplo individual não deve ser gravado verticalmente ou espalhado por várias linhas. Você pode escolher como separa a representação de peças na saída.
Premissas
Nós podemos assumir isso n >= k > 0
.
fonte
(0, 4, 4)
por si só? Dada a sua descrição, eu acho que seria a sua "parte"(0, 4, 4), (1, 4, 4), (2, 4, 4), (3, 4, 4), (4, 4, 4)
. Da mesma forma,(0, 0, 3, 3)
no segundo caso de teste.Respostas:
Geléia ,
2625 bytesPrograma completo que imprime uma representação de uma lista de listas, cada uma fazendo parte, por exemplo, para n = 5, k = 3:
Nota: a representação usada remove as listas redundantes
[
e em]
torno do comprimento 1.Experimente online! ou veja uma versão impressa bonita (custo 3 bytes)
Como?
fonte
MATLAB, 272 bytes
Resultado:
Duas linhas vazias entre partes diferentes.
Ungolfed:
Explicação:
Primeiro, encontramos todos os multisets com força bruta:
repmat(0:n-1, 1, k)
repete o vetor de valores de0
paran-1
k
vezes.nchoosek(x, k)
retorna uma matriz contendo todas as combinações k do vetor repetido.sort(x, 2)
classifica todas as combinações k eunique(x, 'rows')
remove todas as duplicatas.p=zeros(0,k);
cria uma matriz vazia comk
colunas. Vamos usá-lo como uma pilha. Em cada iteração do outernmostfor
loop, que primeiro adicionar o multiset atual para a referida pilha:p=[p;l(i,:)];
.Em seguida, verificamos se a interseção de todos os multisets na pilha é pelo menos
k-1
longa com o código a seguir (não podemos usar ointersect
comando do MATLAB para verificar as interseções, pois ele retorna um conjunto, mas precisamos de um multiset):Agora, se a interseção for longa o suficiente
a == 0
, caso contrárioa == 1
.Se a interseção não for longa o suficiente, imprimimos uma nova linha e esvaziamos a pilha:
Em seguida, apenas imprimimos o multiset atual:
fonte
MATL , 34 bytes
As peças são separadas por uma linha que contém espaços em branco.
Experimente online!
Explicação
Isenção de responsabilidade: este método parece funcionar (e funciona nos casos de teste), mas não tenho uma prova de que sempre funcione
As multisets são classificadas internamente (ou seja, cada multiset possui entradas não decrescentes) e externamente (ou seja, o multiset M vem antes do multiset N se M precede N lexicograficamente).
Para calcular a interseção multiset, os multisets classificados são organizados como linhas de uma matriz e as diferenças consecutivas são calculadas ao longo de cada coluna. Se todas as colunas, exceto no máximo uma, tiverem todas as diferenças iguais a zero, os vários conjuntos pertencerão à mesma parte.
Este teste daria um resultado falso negativo para multisets como
(1,2,3)
e(2,3,4)
: mesmo se2
,3
são entradas comuns, eles não seriam detectados como tal, porque eles estão em colunas não correspondentes.No entanto, isso não parece ser um problema, pelo menos nos casos de teste. Parece que um teste entre multisets como
1,2,3
e2,3,4
nunca precisa ser feito, porque alguns multisets intermediários deram um resultado negativo e, portanto, eles já estão em partes diferentes. Se isso é realmente verdade, o motivo, sem dúvida, tem a ver com o fato de os multisets serem classificados.Eu não tenho uma prova disso, no entanto. Parece apenas funcionar.
fonte
n=k=4
caso de começarmos uma nova peça(0, 0, 3, 3)
, a diferença consecutiva vetorizada disso e do conjunto múltiplo anterior(0, 0, 2, 3)
tem apenas uma diferença; então, como a "peça até agora" faz isso funcionar? (ou equivalentemente qual foi o resultado etapa anterior que foi usado em vez de(0, 0, 2, 3)
?)PHP, 245 bytes
Experimente online!
Expandido
Saída como String
n> 15 para mais precisão
fonte
0
para(16**16-1)%16
e do longo trabalho versão somente com a precisão que é necessário paran>15
bcmod(bcsub(bcpow(16,16),1),16)
se15
php.net/manual/en/ref.bc.php