Subconjunto máximo por pares não divisível por

8

Eu tenho um conjunto de números, e quer calcular o máximo subconjunto tal que a soma de quaisquer dois de seu elementos não é divisível por um inteiro . Tentei resolver esse problema, mas encontrei a solução quadrática, que não é uma resposta eficiente. , onde é o número de elementos e é constante. Existe melhor que solução quadrática?K
K<100,N<10000NK

manduinca
fonte
Você poderia descrever sua solução? Tem certeza de que existe uma solução melhor? A edição preservou suas intenções?
Mal
Você pode encontrar algumas soluções neste link .
Gadheyan .ts
@ Gadheyan.ts o problema que você mencionou é um caso muito especial desse problema. Nesse problema, o conjunto de números fornecido está na forma de , enquanto aqui temos um conjunto arbitrário de números. O problema que você mencionou pode ser resolvido em . {1,2,,N}O(1)
Orezvani 30/05

Respostas:

13

De fato, existe um algoritmo de tempo linear para isso. Você só precisa usar alguns conceitos básicos da teoria dos números. Dados dois números e , sua soma é divisível para , somente se a soma de sua restante é divisível para . Em outras palavras,n1n2KK

K(n1+n2)        K((n1 mod K)+(n2 mod K)).

O segundo conceito que você precisa considerar é que, a soma de dois números é , apenas se um deles for estritamente menor que e o outro não for menor que . Em outras palavras,r1r2KK/2K/2

r1+r2=K      r1<K/2, r2K/2      (r1r2, w.l.g. r1<r2).

O terceiro conceito que você precisa considerar é que, se a soma dos dois números for , ambos se desviarão de por um certo , ou seja,r1r2KK/21kK/2

r1+r2=K      kK/21   such that   r1=K/21k, r2=K/2+k.

Portanto, para evey no terceiro conceito, você precisa colocar ou no conjunto de soluções, mas não os dois. Você pode colocar um dos números que são realmente divisíveis por e, se for par, você poderá adicionar apenas um número cujo restante seja .kr1r2KKK/2

Portanto, aqui está o algoritmo.

Dado um conjunto , vamos encontrar o conjunto de soluçõesN={n1,n2,,nN}S,

  1. ConsidereR={r1=(n1 mod K),r2=(n2 mod K),,rN=(nN mod K)}
  2. S
  3. para no :k1K/21
  4. se :count(R,k)count(R,Kk)
  5. adiciona todos os a , de modo queniSri=k
  6. else:
  7. adiciona todos os a , de modo queniSri=Kk
  8. adicione apenas um a , para que // se existirniSri=0
  9. se é par:K
  10. adicione apenas um a modo que // se existirniSri=K/2
  11. SaídaS

O algoritmo é bastante longo, mas a ideia é muito simples.

orezvani
fonte
@ DW eu assumi que . Eu deliberadamente coloquei essa suposição para evitar números pares; Eu adicionei o seguinte: "wlg "r1r2r1<r2
orezvani
@DW Não evita completamente números pares. Se você prosseguir, verá por que coloquei esse conceito / lema. Basicamente, para o número par , se o restante de alguns s for exatamente , então estamos interessados ​​em apenas um desses s (se colocarmos mais de um, violaremos a condição da pergunta). Por isso, tratei todos esses com essa condição separadamente. KniK/2nini
Orezvani 27/05
@DW eu coloquei wlg para . Eu acho que isso foi realmente desnecessário, mas eu coloquei apenas por questão de convenções. r1<r2
orezvani 27/05
OK, entendo o que você quer dizer agora! Obrigado por explicar.
DW
1

Considere um conjunto S de tamanho n contendo todos os números naturais distintos. Temos que formar o subconjunto máximo desse conjunto. Usamos uma propriedade de módulo básico e adicionamos algumas deduções para resolver o problema. Espero que seja útil para todos vocês.

Para quaisquer dois números naturais N1 e N2: (N1 + N2) mod (K) = (R1 + R2) mod (K) em que R1 = N1modK e R2 = N2% K. 1. Se nós (N1 + N2) modK = 0, isso significa (R1 + R2)% K = 0. 2. Isso significa que R1 + R2 deve ser igual a K, 2K, 3K .... 3. Mas R1 fica entre 0 e K-1 e R2 também, o que significa que sua soma não pode exceder K-1 + K-1 = 2 (K-1). 4. De 2 e 3, podemos concluir que R1 + R2 deve ser igual a K. 5. Além disso, se R1 + R2 = K significa que ambos devem ser iguais a K / 2 (somente possível se K for par) ou um deles deve ser menor que o piso [K / 2] e outro maior que o mesmo. 6. Suponha que R1 = T e R2 = KT, se pegarmos qualquer número N1 de S cujo restante é R1 e qualquer número N2 de S cujo restante é R2, sua soma será divisível por K. Portanto, o subconjunto Solução pode ter aqueles números com o restante R1 ou aqueles com o restante R2, mas não ambos.

Agora, suponha que construamos uma matriz R do tamanho K com o índice 0 a K-1. O elemento em cada índice indica o número de números no conjunto S com o restante (na divisão com K) igual ao número do índice. Não podemos ter mais de 2 números com o restante 0, pois sua soma seria divisível por K; portanto, devemos inicializar nosso contador com min (R [0], 1). Para T = 1 a T

O código para o mesmo algoritmo em C ++ é como mostrado abaixo:

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;


int main() {

    int n,k;
    cin>>n>>k;
    vector <int> a(n);
    vector <int> r(k,0);
    for(int i=0;i<n;i++)
    {   
        cin>>a[i];
        r[a[i]%k]++;
    }
    int ctr=min(1,r[0]);
    for(int a=1;a<(k/2+1);a++)
        {
            if(a!=k-a)
                ctr+=max(r[a],r[k-a]);
        }
    if(k%2==0&&r[k/2]!=0)
        ctr++;
    cout<<ctr;
    return 0;
}
Dhruva Bhagdikar
fonte
Você poderia traduzir seu código em pseudocódigo?
mal
1. Leia k, n 2. Faça duas matrizes A e R do tamanho n e k 3. i = 0, ctr = 0, a = 1 4. enquanto (i <n) lê A [i] R [A [ i]% k] ++ i = i + 1 final enquanto 5. ctr = mínimo (1, R [0]) 6. enquanto (a <k / 2 + 1) faça se (a! = ka) ctr = ctr + máximo (R [a], R [ka]) endif a = a + 1 ao final 7. se (k fornecer 0 restante quando dividido por 2 e R [k / 2] for diferente de zero) ctr = ctr + 1 8. print ctr 9. Fim
Dhruva Bhagdikar
Eu quis dizer no post, usando edit, desculpe pelo inconveniente e obrigado pelo pseudocódigo.
Mal
0

Tentei traduzir para código C #, o primeiro a contar apenas o tamanho da matriz de subconjuntos e o outro incluindo o subconjunto inteiro (hash).

Contagem:

static int nonDivisibleSubset(int k, int[] S)
{
    var r = new int[k];

    for (int i = 0; i < S.Length; i++)
        r[S[i] % k]++;

    int count = Math.Min(1, r[0]); 

    if (k % 2 == 0 && r[k / 2] != 0) 
        count++;                                    

    for (int j = 1; j <= k / 2; j++) 
    {                                                         
        if (j != k - j)
            count += Math.Max(r[j], r[k - j]);
    }

    return count;
}

Com subconjunto:

static int nonDivisibleSubset(int K, int[] S)
{
    var r = new HashSet<int>();
    var d = S.GroupBy(gb => gb % K).ToDictionary(Key => Key.Key, Value => Value.ToArray());

    for (int j = 1; j <= K / 2; j++)
    {
        var c1 = d.GetValueOrDefault(j, new int[0]);
        var c2 = d.GetValueOrDefault(K - j, new int[0]);

        if (c1.Length == c2.Length) continue;

        r.UnionWith(c1.Length > c2.Length ? c1 : c2);
    }

    if (d.ContainsKey(0))
        r.Add(d[0].Max());

    if (K % 2 == 0 && d.ContainsKey(K / 2))
        r.Add(d[K / 2].Max());

    return r.Count;
}
Grande chefe
fonte
1
Este não é um site de codificação.
Yuval Filmus
este é um site de matemática?
BigChief 12/08/19
A extensão exata do site é difícil de definir. Você pode olhar ao redor para ver quais perguntas são fechadas e quais não.
Yuval Filmus
Minha intenção era adicionar um pouco mais de profundidade ao código já publicado, e o último bloco de código retorna um subconjunto que maximiza explicitamente o subconjunto completo em vez de retornar apenas o tamanho do subconjunto. Espero que isso seja útil para quem tenta entender o problema em questão. Também espero receber feedback sobre a correção. A publicação de código ou equações matemáticas tem alguma equivalência?
BigChief 12/08/19
Normalmente, o código de postagem é mal visto. Preferimos pseudocódigo ou uma descrição textual.
Yuval Filmus