Dividere il numero intero in modo che entrambi i lati siano numeri primi

6

Il problema

Ti viene assegnato un n numero. Verifica se il numero n può essere diviso a metà in modo che entrambi i lati di | siano numeri primi.

Esempio:

Input Output

223   2|23
123   Not possible to split.

La mia idea

Mi è stato fornito un esempio di n numero che ha solo tre cifre, e in tal caso sarebbe facile completare l'operazione, ma non è stato stabilito che il n sarà composto da tre cifre, quindi questo rende il problema molto più complesso, secondo me.

Quindi se n potrebbe avere m numero di cifre, farei il successivo. Converti un numero intero in un array e poi implementa una sorta di algoritmo divide et impera. Tuttavia, non sono sicuro di come procederò a confrontare ciascun elemento con il resto degli elementi.

Qualcuno ha qualche idea su come posso completare l'algoritmo? Inoltre, nulla è scolpito nella pietra quindi qualsiasi altro suggerimento sarebbe più che benvenuto.

Aggiornamento

Grazie a tutti ho finito l'algoritmo. Inserirò il mio codice qui sotto.

#include <iostream>
#include <cmath>

using namespace std;

int numberOfDigits(int n)
{
    int digits = 0;
    if(n < 0)
        digits = 1;
    while(n)
    {
        n /= 10;
        digits++;
    }
    return digits;
}

bool isPrime(int n)
{
    int isPrime = true;
    for(int i = 2; i <= sqrt(n); i++)
    {
        if(n % i == 0)
        {
            isPrime = false;
            break;
        }
    }

    if(isPrime && n > 1)
        return true;
    else
        return false;
}

int removeLastDigits(int n, int count)
{       
    return n / pow(10, count);
}

int getLastDigits(int n, int count)
{       
    return n % (int)pow(10, count);
}

void findPair(int n, int m)
{
    int a = n;
    int b = m;
    int counter = 1;
    int digits = numberOfDigits(n);
    int arePrimes = 0;

    while(digits >= 1)
    {
        if(isPrime(a) && isPrime(b))
        {
            cout << a <<"|" << b << endl;
            arePrimes = 1;
            break;
        }
        else
        {
            a = removeLastDigits(n, counter);
            b = getLastDigits(n, counter);
            counter++;
            digits--;
        }
    }


    if(arePrimes == 0)
        cout << "Not possible to split." << endl;
}

int main()
{
    int n;
    cout << "Enter the number: ";
    cin >> n;
    findPair(n, 0);
}
    
posta brajevicm 13.10.2016 - 18:03
fonte

5 risposte

3

Per prima cosa crea l'elenco dei numeri da controllare in base al numero iniziale.

Esempio: 253

Assumi dividi solo una volta.

I numeri Dal numero iniziale: [2,53], [25,3]

Nota, si potrebbe fare un po 'di doppione anche qui per evitare di elaborare due volte lo stesso numero (Esempio: 111 ha solo due numeri 1, 11).

Ciascuna di queste "coppie divise" può essere controllata se ogni numero è primo.

If (IsPrime (2) e IsPrime (53)) = > allora vero
If (IsPrime (25) e IsPrime (3)) = > quindi falso (25 non è primo)

Quindi, invia semplicemente ogni numero al setaccio numerico IsPrime (). (Eratostene, ecc.) In questo caso i numeri da controllare per primo sono 2,53,25,3. Quindi "And Logic Gate" ogni coppia divisa per la risposta finale. Si potrebbe parallelizzare IsPrime () per l'elaborazione di più numeri allo stesso tempo.

Ci sono alcune scorciatoie. Se il numero originale termina in 4,6,8, o zero, qualsiasi "coppia divisa" sarà sempre valutata come falsa poiché uno dei numeri nella coppia è pari e mai primo. (@Andres F., @ user949300) Quindi, si potrebbe fare prima questo controllo piuttosto che eseguire tutti i numeri attraverso il setaccio come cortocircuito per salvare la CPU. Sono sicuro che ci sono anche altri trucchi.

    
risposta data 13.10.2016 - 23:16
fonte
2

Il mio primo pensiero è stato un approccio proveniente dalla direzione opposta a @ Jon Raynors. Non sono sicuro di quale sia il migliore, (penso che sia probabilmente più veloce) ma eccolo qui.

Se il numero ha N cifre, generare (o avere pre-calcolato) tutti i numeri primi di meno di N cifre. Convertili tutti in stringhe. Quindi, organizzali in array di array di lunghezza. per es.

allPrimes[0] = [],
allPrimes[1] = ["1", "2", "3", "5", "7"];  // I forget, is 1 prime???

Quindi un ciclo (codice Java qui)

String testValue = String.valueOf(n);
int digits = testValue.length();

for (int i=1; i<digits; i++)
   for (String p1: allPrimes[i])
      for (String p2: allPrimes[digits-i])
         if (testValue.equals(p1+p2))
            return "matched for " + p1 + "|" + p2;

return "no match";

Come altri hanno notato, qualsiasi numero che termina con 4,6,8 o 0 può essere eliminato all'istante.

    
risposta data 13.10.2016 - 23:59
fonte
0

Per prima cosa matematica: se n è dispari allora un numero deve essere uguale a 2 e n-2 deve essere primo. Se n = 4 allora n = 2 + 2. Se n > = 6 è pari allora dovrebbe essere la somma di un primo dispari ≤ n / 2 e un numero dispari ≥ n / 2.

Le probabilità che un numero dispari grande p sia primo sono di circa 2 / ln p. Crea un setaccio per trovare i numeri primi da n - 5 (ln p) ^ 2 a n - 1, quindi controlla se c'è un primo p in quel setaccio dove anche n - p è primo. Se non riesci a trovarne uno, ingrandisci il setaccio.

Non ho il minimo indizio su come "dividere e conquistare" verrebbe in questo.

    
risposta data 13.10.2016 - 20:55
fonte
0

Sei corretto, un array è un metodo efficace per iniziare. Il modo in cui finisci per farlo si riduce alle tue preferenze di codifica, ma probabilmente vorrai iniziare come segue.

Per prima cosa è necessaria una funzione per verificare se un input è o meno in primo piano. Come si codifica che è in gran parte personale, di solito finisce per essere un ciclo con un operatore modulo. Seguo il paradigma di programmazione funzionale, quindi il mio codice sarebbe simile a questo:

* Nota: ci sono algoritmi mathamatici che lo fanno in modo più efficiente, ho appena scritto questo perché è facile ragionare.

function isPrime(x, y = Math.floor(x/2)){
  // x is input. Anything greater than half of x can't be divided into it
  cleanly.

  /*if our starting value is less than 3, it's automatically not prime.
  if(x < 3){
    return false;
  }

  //Does y fit into x cleanly? Yes? Then it can't be prime.
  if(x % y === 0){
    return false;
  }

  /*We've counted y down to 2. 2 nor any of the numbers before it have fit
  into x, therefore x is prime.*/
  if(y <= 2){
    return true;
  }

  /*assuming nothing else fit, we're ready to try again. This time with y
  as a lower value*/
  return isPrime(x,y-1);
}

Ora che possiamo facilmente verificare se un numero è primo, tutto ciò che dobbiamo fare è scorrere il numero.

Diciamo che il nostro numero iniziale è 1234 . Per prima cosa lo trasformeremo in un array, [1,2,3,4] . Poi avremmo ragione un'altra funzione per concatenare automaticamente la nostra matrice come necessario e controllare i primi. Faremo qualcosa del genere:

split the array at the first position [1,2,3,4] becomes 1|234
  Is 1 prime?
    Yes: is 234 Prime?
      Yes: return "These numbers can be split.";
      No: next step;
    No: next step;

split the array at the second position [1,2,3,4] becomes 12|34
  Is 12 prime?
    Yes: is 34 Prime?
      Yes: return "These numbers can be split.";
      No: next step;
    No: next step;

split the array at the second position [1,2,3,4] becomes 123|4
  Is 123 prime?
    Yes: is 4 Prime?
      Yes: return "These numbers can be split."
      No: next step;
    No: return "These numbers can't be split.";

Esegui qualcosa di simile in un ciclo che si esegue un numero di volte uguale a 1 in meno della lunghezza della matrice (perché le spaccature | 1234 e 1234 | non hanno significato). Per quanto riguarda le concatenazioni e il lavoro con gli array, questo è un argomento per un'altra volta. In generale, varia leggermente da una lingua all'altra.

    
risposta data 14.10.2016 - 08:40
fonte
0

Se il numero non finisce in 1, 3, 7 o 9, qualsiasi numero preso dalla destra della stringa con due o più cifre non può essere un numero primo, quindi si controlla se l'ultima cifra è 2 o 5 e le prime cifre n-1 sono un numero primo.

Se il numero termina in 1, 3, 7 o 9, allora provi tutte le combinazioni di cifre k dalle cifre sinistra e nk da destra, per 1 ≤ k ≤ n-1 nell'ordine k = 1, n -1, 2, n-2, 3, n-3 ecc. Perché in questo modo, si tende ad avere un numero piccolo più facile da controllare per la primalità.

Il modo ovvio sarebbe controllare che il numero di sinistra sia un numero primo, quindi verificare che il numero corretto sia un numero primo, o nell'ordine opposto. Tuttavia, questo è abbastanza inefficiente se si dispone di un numero primo di 30 cifre e un numero di 70 cifre divisibile per 7, ad esempio.

Invece, controlli un certo intervallo di piccoli numeri primi p se entrambi i numeri sono divisibili per p - ciò migliora le tue possibilità di dimostrare rapidamente che un numero non è primo. Una volta che hai testato abbastanza divisori di prova, usi il test Miller-Rabin alternando entrambi i numeri per dimostrare che uno è composito. Se fallisce, fai un test di primalità per entrambi i numeri.

Nota che se hai numeri casuali, è molto più probabile che siano compositi, e molto probabilmente che almeno uno dei due è composto, quindi il tempo di esecuzione non sarà troppo cattivo, a meno che il numero può essere diviso perché allora dovrai dimostrare che due numeri di cui almeno uno è grande sono entrambi numeri primi.

    
risposta data 15.10.2016 - 01:06
fonte

Leggi altre domande sui tag