Sottoinsieme massimo a coppie non divisibile per


8

Ho un insieme di numeri e desidero calcolare il sottoinsieme massimo in modo tale che la somma di due dei suoi elementi non sia divisibile per un numero intero K. Ho provato a risolvere questo problema, ma ho trovato la soluzione quadratica, che non è una risposta efficiente.
K<100,N<10000, dove N è il numero di elementi e Kè dato costante. C'è di meglio della soluzione quadratica?


Potresti descrivere la tua soluzione? Sei sicuro che esista una soluzione migliore? La modifica ha conservato le tue intenzioni?
Evil

Puoi trovare alcune soluzioni su questo link .
Gadheyan .ts,

@ Gadheyan.ts il problema che hai citato è un caso molto speciale di questo problema. In quel problema, il dato set di numeri ha una forma di{1,2,,N}, mentre qui abbiamo una serie arbitraria di numeri. Il problema che hai citato può essere risoltoO(1).
orezvani,

Risposte:


13

In effetti esiste un algoritmo di tempo lineare per questo. Hai solo bisogno di usare alcuni concetti di base della teoria dei numeri. Dati due numerin1 e n2, la loro somma è divisibile per K, solo se la somma del resto è divisibile per K. In altre parole,

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

Il secondo concetto che devi considerare è quello, la somma di due numeri r1r2 è K, solo se uno di questi è strettamente più piccolo di K/2 e l'altro non è inferiore a K/2. In altre parole,

r1+r2=K      r1<K/2, r2K/2      (r1r2, wlg r1<r2).

Il terzo concetto che devi considerare è quello, se la somma di due numeri r1r2 è K, entrambi si discostano K/2-1 da un certo KK/2cioè

r1+r2=K      KK/2-1   tale che   r1=K/2-1-K, r2=K/2+K.

Quindi, per evey K nel terzo concetto, è necessario inserire entrambi r1 o r2nel set di soluzioni, ma non entrambi. È consentito inserire uno dei numeri che sono effettivamente divisibili perK e se K è pari, puoi aggiungere solo un numero che sia il resto K/2.

Pertanto, ecco l'algoritmo.

Dato un set N={n1,n2,,nN}, troviamo il set di soluzioni S,

  1. Prendere in considerazione R={r1=(n1 mod K),r2=(n2 mod K),,rN=(nN mod K)}
  2. S
  3. per k1 per K/21:
  4. Se count(R,k)count(R,Kk):
  5. Aggiungi tutto ni per S, tale che ri=k
  6. altro:
  7. Aggiungi tutto ni per S, tale che ri=Kk
  8. aggiungere solo uno ni per S tale che ri=0// se esiste
  9. Se K è anche:
  10. aggiungere solo uno ni per S tale che ri=K/2// se esiste
  11. Produzione S

L'algoritmo è piuttosto lungo, ma l'idea è molto semplice.


@DW l'ho assunto r1r2. Ho deliberatamente formulato tale presupposto per evitare numeri pari; Ho aggiunto quanto segue: "wlgr1<r2"
orezvani,

@DW Non evita completamente i numeri pari. Se procedi, vedrai perché ho messo tale concetto / lemma. Fondamentalmente, per un numero pariK, se il resto di alcuni nisono esattamente K/2, quindi siamo interessati solo a uno di quelli nis (se ne inseriamo più di una, violeremo la condizione della domanda). Ecco perché, ho trattato tutto questonis con quella condizione separatamente.
orezvani,

@DW ho messo wlg per r1<r2. Penso che sia stato davvero inutile, ma l'ho messo solo per la questione delle convenzioni.
orezvani,

OK, capisco cosa intendi adesso! Grazie per aver spiegato.
DW

1

Considera un set S di dimensione n contenente tutti i numeri naturali distinti. Dobbiamo formare il sottoinsieme massimo da questo set. Usiamo una proprietà del modulo di base e aggiungiamo alcune deduzioni per risolvere il problema. Spero sia utile per tutti voi.

Per due numeri naturali N1 e N2: (N1 + N2) mod (K) = (R1 + R2) mod (K) dove R1 = N1modK e R2 = N2% K. 1. Se noi (N1 + N2) modK = 0 significa (R1 + R2)% K = 0. 2. Ciò significa che R1 + R2 deve essere uguale a K, 2K, 3K .... 3. Ma R1 è compreso tra 0 e K-1 e quindi anche R2, il che significa che la loro somma non può superare K-1 + K-1 = 2 (K-1). 4. Da 2 e 3 possiamo concludere che R1 + R2 deve essere uguale a K. 5. Inoltre, se R1 + R2 = K significa che entrambi devono essere uguali a K / 2 (possibile solo se K è pari) o uno di questi deve essere inferiore al piano [K / 2] e uno maggiore dello stesso. 6. Supponiamo che R1 = T e R2 = KT, se prendiamo un numero N1 da S il cui resto è R1 e qualsiasi numero N2 da S il cui resto è R2, la loro somma sarà divisibile per K. Pertanto il sottoinsieme Soluzione può avere entrambi numeri con resto R1 o quelli con resto R2 ma non entrambi.

Supponiamo ora di costruire un array R di dimensioni K con indice da 0 a K-1, l'elemento in ciascun indice che denota il numero di numeri nell'insieme S con resto (sulla divisione con K) uguale al numero di indice. Non possiamo avere più di 2 numeri con il resto 0 poiché la loro somma sarebbe divisibile per K, quindi dobbiamo inizializzare il nostro contatore con min (R [0], 1). Per T = 1 a T

Il codice per lo stesso algoritmo in C ++ è come mostrato di seguito:

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

Potresti tradurre il tuo codice in pseudocodice?
Evil

1. Leggi k, n 2. Crea due matrici A e R delle dimensioni n e k 3. i = 0, ctr = 0, a = 1 4. mentre (i <n) legge A [i] R [A [ i]% k] ++ i = i + 1 mentre 5. ctr = minimo (1, R [0]) 6. mentre (a <k / 2 + 1) fa se (a! = ka) ctr = ctr + massimo (R [a], R [ka]) endif a = a + 1 endwhile 7. if (k dà 0 resto quando diviso per 2 e R [k / 2] è diverso da zero) ctr = ctr + 1 8. stampa ctr 9. Fine
Dhruva Bhagdikar,

Nel post ho voluto dire, usando modifica, scusate l'inconveniente e grazie per lo pseudocodice.
Evil

0

Ho provato a tradurre in codice C #, il primo a contare solo le dimensioni dell'array del sottoinsieme e un altro compreso l'intero sottoinsieme (hash).

Contare:

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 sottoinsieme:

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

1
Questo non è un sito di codifica.
Yuval Filmus,

è un sito di matematica?
BigChief,

L'esatta estensione del sito è difficile da definire. Puoi guardarti intorno per vedere quali domande vengono chiuse e quali no.
Yuval Filmus,

Il mio intento era quello di aggiungere un po 'più di profondità al codice già pubblicato, anche quest'ultimo blocco di codice restituisce un sottoinsieme che massimizza esplicitamente il sottoinsieme completo invece di restituire solo la dimensione del sottoinsieme. Speriamo che questo sia utile a chiunque cerchi di capire il problema in questione. Spero anche di ricevere feedback sulla correttezza. Postare codice o equazioni matematiche ha qualche equivalenza?
BigChief,

Il codice postale è generalmente disapprovato. Preferiamo lo pseudocodice o una descrizione testuale.
Yuval Filmus
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.