Subconjunto máximo por pares no divisible por

8

Tengo un conjunto de números y quiero calcular el subconjunto máximo de modo que la suma de cualquiera de sus dos elementos no sea divisible por un entero K. Traté de resolver este problema, pero encontré la solución cuadrática, que no es una respuesta eficiente.
K<100,N<10000, dónde N es el número de elementos y Kse da constante ¿Hay una solución mejor que la cuadrática?

manduinca
fuente
¿Podría describir su solución? ¿Estás seguro de que existe una mejor solución? ¿La edición conservó tus intenciones?
Mal
Puede encontrar algunas soluciones en este enlace .
Gadheyan .ts
@ Gadheyan.ts el problema que mencionó es un caso muy especial de este problema. En ese problema, el conjunto de números dado está en forma de{1,2,,N}, mientras que aquí tenemos un conjunto arbitrario de números. El problema que mencionaste puede resolverse enO(1).
orezvani

Respuestas:

13

De hecho, hay un algoritmo de tiempo lineal para esto. Solo necesita usar algunos conceptos básicos de teoría de números. Dados dos númerosn1 y n2, su suma es divisible a K, solo si la suma de su resto es divisible a K. En otras palabras,

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

El segundo concepto que debe tener en cuenta es que, la suma de dos números r1r2 es K, solo si uno de ellos es estrictamente más pequeño que K/2 y el otro no es menos que K/2. En otras palabras,

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

El tercer concepto que debe tener en cuenta es que, si la suma de dos números r1r2 es K, ambos se desvían de K/21 por cierto kK/2es decir,

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

Entonces, para todos k en el tercer concepto, necesitas poner r1 o r2en el conjunto de soluciones, pero no en ambos. Se le permite poner uno de los números que son divisibles porK y si K es par, solo puede agregar un número cuyo resto es K/2.

Por lo tanto, aquí está el algoritmo.

Dado un conjunto N={n1,n2,,nN}, busquemos el conjunto de soluciones S,

  1. Considerar R={r1=(n1 mod K),r2=(n2 mod K),,rN=(nN mod K)}
  2. S
  3. para k1 a K/21:
  4. Si count(R,k)count(R,Kk):
  5. añadir todo ni a Stal que ri=k
  6. más:
  7. añadir todo ni a Stal que ri=Kk
  8. agrega solo uno ni a S tal que ri=0// si existe
  9. Si K incluso:
  10. agrega solo uno ni a S tal que ri=K/2// si existe
  11. Salida S

El algoritmo es bastante largo, pero la idea es muy simple.

orezvani
fuente
@DW asumí que r1r2. Deliberadamente pongo tal suposición para evitar números pares; Agregué lo siguiente: "wlgr1<r2"
orezvani
@DW No evita completamente los números pares. Si continúas, verás por qué he puesto ese concepto / lema. Básicamente, para un número parK, si el resto de algunos nis son exactamente K/2, entonces solo nos interesa uno de esos nis (si ponemos más de uno, violaremos la condición de la pregunta). Es por eso que traté a todosnis con esa condición por separado.
orezvani
@DW puse wlg para r1<r2. Creo que eso fue realmente innecesario, pero lo expresé solo por cuestiones de convenciones.
orezvani
OK, ¡entiendo a qué te refieres ahora! Gracias por la explicación.
DW
1

Considere un conjunto S de tamaño n que contiene todos los números naturales distintos. Tenemos que formar el subconjunto máximo a partir de este conjunto. Usamos una propiedad de módulo básico y le agregamos algunas deducciones para resolver el problema. Espero que sea útil para todos ustedes.

Para dos números naturales N1 y N2: (N1 + N2) mod (K) = (R1 + R2) mod (K) donde R1 = N1modK y R2 = N2% K. 1. Si nosotros (N1 + N2) modK = 0 significa (R1 + R2)% K = 0. 2. Eso significa que R1 + R2 debe ser igual a K, 2K, 3K .... 3. Pero R1 se encuentra entre 0 y K-1 y R2 también, lo que significa que su suma no puede exceder K-1 + K-1 = 2 (K-1). 4. De 2 y 3 podemos concluir que R1 + R2 debe ser igual a K. 5. Además, si R1 + R2 = K eso significa que ambos deben ser iguales a K / 2 (solo posible si K es par) o uno de ellos debe ser menor que el piso [K / 2] y uno mayor que el mismo. 6. Suponga que R1 = T y R2 = KT, si tomamos cualquier número N1 de S cuyo resto es R1 y cualquier número N2 de S cuyo resto es R2, entonces su suma será divisible por K. Por lo tanto, el subconjunto de la Solución puede tener esos números con el resto R1 o aquellos con el resto R2 pero no ambos.

Ahora supongamos que construimos una matriz R de tamaño K con índice de 0 a K-1. El elemento en cada índice denota el número de números en el conjunto S con resto (en la división con K) igual al número de índice. No podemos tener más de 2 números con su resto 0 ya que su suma sería divisible por K, por lo tanto, debemos inicializar nuestro contador con min (R [0], 1). Para T = 1 a T

El código para el mismo algoritmo en C ++ es el que se muestra a continuación:

#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
fuente
¿Podría traducir su código a seudocódigo?
Mal
1. Lee k, n 2. Haz dos matrices A y R de tamaño n y k 3. i = 0, ctr = 0, a = 1 4. mientras que (i <n) lee A [i] R [A [ i]% k] ++ i = i + 1 endwhile 5. ctr = mínimo (1, R [0]) 6. while (a <k / 2 + 1) do if (a! = ka) ctr = ctr + máximo (R [a], R [ka]) endif a = a + 1 end while 7. if (k da 0 resto cuando se divide entre 2 y R [k / 2] no es cero) ctr = ctr + 1 8. print ctr 9. Fin
Dhruva Bhagdikar
Me he referido a la publicación, al usar editar, disculpe las molestias y gracias por el pseudocódigo.
Mal
0

Intenté traducir al código C #, el primero en contar solo el tamaño de la matriz de subconjuntos y otro que incluye todo el subconjunto (hash).

Contar:

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;
}

Con 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;
}
Gran jefe
fuente
1
Este no es un sitio de codificación.
Yuval Filmus el
¿Es este un sitio de matemáticas?
BigChief
La extensión exacta del sitio es difícil de definir. Puede mirar alrededor para ver qué preguntas se cierran y cuáles no.
Yuval Filmus el
Mi intención era agregar más profundidad al código ya publicado, también el último bloque de código devuelve un subconjunto que maximiza explícitamente el subconjunto completo en lugar de devolver solo el tamaño del subconjunto. Esperemos que esto sea útil para cualquiera que intente comprender el problema en cuestión. También espero recibir comentarios sobre la corrección. ¿Publicar código o ecuaciones matemáticas tiene alguna equivalencia?
BigChief
El código de publicación generalmente está mal visto. Preferimos pseudocódigo o una descripción textual.
Yuval Filmus