Este é um problema da sessão de treinos do Concurso Polonês de Programação Colegial de 2012 . Embora eu tenha encontrado as soluções para o concurso principal, não consigo encontrar a solução para esse problema em nenhum lugar.
O problema é: dado um conjunto de números inteiros positivos distintos não maiores que , encontre o tamanho do subconjunto menor que não possui divisor comum além de 1. é no máximo 500 e é possível presumir que existe uma solução .10 9 m N
Consegui mostrar que meu número . Meu raciocínio é: Suponha que exista um subconjunto mínimo de tamanho , com gcd = 1. Então todos os 9 subconjuntos de devem ter gcd> 1. Existem exatamente 10 desses subconjuntos e seus gcds devem ser pareados coprime. Seja esses gcds , onde , para i \ neq j . Então o número máximo em S é g_2g_3 ... g_ {10} . Mas g_2g_3 ... g_ {10} \ ge 3 \ times5 \ times7 \ times11 \ times ... \ times29 = 3234846615> 10 ^ 9 , uma contradição.
No entanto, mesmo com isso, uma força bruta direta ainda é muito lenta. Alguém tem outras idéias?
fonte
Respostas:
Esse problema é equivalente ao seguinte e é trivial construir redução nos dois sentidos.
Dada uma lista de vetores de bits, encontre o número mínimo deles para que0 (∗)
and
todos resultem no vetor de bits.Em seguida, mostramos a cobertura do conjunto reduzida para . Por cobertura de conjunto, quero dizer, com uma lista dos conjuntos , encontre o número mínimo de conjuntos que cobre sua união.(∗) S1,…,Sk
Ordenamos que os elementos nos conjuntos sejam . Seja , onde se , 0 caso contrário. Note que esta função é uma bijeção e, portanto, tem uma inversa.a1,…,an f(S)=(1−χa1(S),…,1−χan(S)) χx(S)=1 x∈S
Agora, se resolvermos em e as soluções forem , então é a solução para se proteger.(∗) f(S1),…,f(Sk) {f(Sb1),…,f(Sbm)} {f−1(Sb1),…,f−1(Sbm)}
Assim, eu pensaria que esse problema está testando a capacidade de podar o espaço de pesquisa.
fonte
É possível resolver isso de forma relativamente eficiente, computando todos os MDCs em pares, removendo duplicatas e recorrendo novamente. É o ato de remover duplicatas antes de você recursar que a torna eficiente.
Vou explicar o algoritmo com mais detalhes abaixo, mas primeiro, ele ajuda a definir um operador binário . Se são conjuntos de números inteiros positivos, defina⊗ S,T
Observe quee (no seu problema); normalmente, será ainda menor do que qualquer um desses limites sugere, o que ajuda a tornar o algoritmo eficiente. Observe também que podemos calcular comoperações gcd por enumeração simples.|S⊗T|≤|S|×|T| |S⊗T|≤109 S⊗T S⊗T |S|×|T|
Com essa notação, aqui está o algoritmo. Seja o conjunto de números de entrada. Calcule , depois , depois e assim por diante. Encontre o menor tal que mas . Então você sabe que o tamanho do menor subconjunto é . Se você também deseja apresentar um exemplo concreto de um subconjunto, mantendo os ponteiros de retorno, é possível reconstruir facilmente esse conjunto.S1 S2=S1⊗S1 S3=S1⊗S2 S4=S1⊗S3 k 1∈Sk 1∉Sk−1 k
Isso será relativamente eficiente, pois nenhum dos conjuntos intermediários aumenta em tamanho acima de (na verdade, seu tamanho provavelmente será muito menor que isso) e o tempo de execução requer cerca de operações gcd.109 500×(|S1|+|S2|+⋯)
Aqui está uma otimização que pode melhorar ainda mais a eficiência. Basicamente, você pode usar a duplicação iterada para encontrar o menor tal que . Em particular, para cada elemento , acompanhamos o menor subconjunto de cujo gcd é e cujo tamanho é . (Ao remover duplicatas, você resolve laços em favor do subconjunto menor.) Agora, em vez de calcular a sequência de nove conjuntos , calculamos a sequência de cinco conjuntos , calculando , depois , em seguida,k 1∈Sk x∈Si S1 x ≤i S1,S2,S3,S4,…,S9 S1,S2,S4,S8,S9 S2=S1⊗S1 S4=S2⊗S2 S8=S4⊗S4 , então . À medida que avança, encontre o primeiro modo que . Depois de encontrar como , é possível parar imediatamente: você pode encontrar o menor subconjunto cujo gcd é observando o subconjunto associado a . Portanto, você pode parar assim que atingir um conjunto tal que , o que permite que você pare mais cedo se encontrar um subconjunto menor.S9=S1×S8 k∈[1,2,4,8,9] 1∈Sk k 1∈Sk 1 1 Sk 1∈Sk
Isso deve ser eficiente em termos de tempo e espaço. Para economizar espaço, para cada elemento , você não precisa armazenar o conjunto inteiro: basta armazenar dois ponteiros traseiros (os dois elementos de quais você tirou o MDC, para obter ) e opcionalmente, o tamanho do subconjunto correspondente.x∈Sk Si,Sj x
Em princípio, você pode substituir a sequência por qualquer outra cadeia de adição . Não sei se alguma outra cadeia de adição será melhor. A escolha ideal pode depender da distribuição de respostas corretas e dos tamanhos esperados dos conjuntos , o que não está claro para mim, mas provavelmente pode ser derivado empiricamente através da experimentação.[1,2,4,8,9] Sk
Créditos: Meus agradecimentos ao KWillets pela idéia de armazenar um subconjunto de números junto com cada elemento de , o que permite parar mais cedo.Si
fonte
Talvez seja mais rápido analisar isso de outra maneira ... o maior número primo menor que é 31607, para uma contagem total de 3401 números primos entre 2 e 31607, não um número muito grande. Escreva cada um dos números que você recebe totalmente fatorado nos números primos até 31607: Aqui é 1 ou um número primo grande. Então, um conjunto de 's é relativamente primo se os vetores correspondentes forem linearmente independentes (e seus forem diferentes ou ambos 1), e você estiver procurando a classificação de uma matriz.109−−−√
fonte
Se você é capaz de encontrar um subconjunto com gcd (S) = 1, sempre posso remover elementos redundantes do subconjunto até restarem apenas 2 elementos, que possuem gcd (S) = 1. Portanto, posso afirmar que o menor subconjunto conterá 2 elementos ou ele não existirá.
Agora, usamos recursão para resolver esse problema. Vamos dividir a matriz de números em 2 partes, uma com n-1 elementos e outra com 1 elemento (último elemento). Os 2 números estarão nos primeiros elementos n-1 ou um elemento estará presente na 1ª parte emparelhado com o último elemento. Portanto, somos capazes de resolver esse problema em
T (n) = T (n-1) + O (n) tempo. o que significa T (n) = O (n ^ 2).
fonte