[A25-51] Il problema dei due addendi

Il forum di Base5, dove è possibile postare problemi, quiz, indovinelli, rompicapo, enigmi e quant'altro riguardi la matematica ricreativa e oltre.

Moderatori: Gianfranco, Bruno

Rispondi
Quelo
Livello 8
Livello 8
Messaggi: 988
Iscritto il: ven giu 16, 2006 3:34 pm

[A25-51] Il problema dei due addendi

Messaggio da Quelo »

"Scrivere un programmino" ha subito attirato la mia attenzione.

Vediamo 3 strategie:
1. La prima si basa sull'iterazione, cioè sul generare tutte le possibili coppie (combinazioni) e verificarne la somma (qui Python ci aiuta perché non dobbiamo scrivere il relativo codice)
2. La seconda consiste nel prelevare un elemento alla volta dalla lista e verificare se nel restante elenco è presente la differenza tra la somma obiettivo e l'elemento prelevato
3. La terza si limta a fare la scansione di tutte le somme con due cicli annidati

Delle tre la numero 2 è la più veloce, mentre la 3 è la più lenta

Codice: Seleziona tutto

from itertools import combinations as cbs
from random import randint


a = input('lista (separati da virgola): ')
somma = int(input('somma obiettivo: '))

if a != '':
    lista = [int(x) for x in a.split(',')]          # converte l'input in una lista
else:
    lista = [randint(1,100) for _ in range(20)]     # crea una lista causale di 20 elementi
    somma = randint(min(lista), max(lista))

print(f'{lista=}')
print(f'{somma=}')

# Metodo con iterazione
n = True
m = []
for c in cbs(lista,2):                              # genera tutte ele possibili coppie
    d = sorted(c)
    if sum(c)==somma and d not in m:                # verifica se la somma corrisponde 
        m.append(d); n = False                      # aggiunge le nuove soluzioni
if n:
    print('nessuna soluzione')
else:
    print(m)

# Metodo con la ricerca
n = True
m = []
for c in range(len(lista)):
    d = lista.copy()                                # crea una copia della lista
    e = d.pop(c)                                    # estrare il numero in posizione c
    f = sorted([e, somma-e])
    if somma-e in d and f not in m:                 # verifica se la differenza è presente nella lista rimanente 
        m.append(f); n = False                      # aggiunge le nuove soluzioni
if n:
    print('nessuna soluzione')
else:
    print(m)

# Metodo con la scansione
n = True
m = []
for c in range(len(lista)):
    for d in range(len(lista)):
        if c!=d:
            e = sorted([lista[c],lista[d]])
            if sum(e)==somma and e not in m:        # verifica se la somma corrisponde 
                m.append(e); n = False              # aggiunge le nuove soluzioni
if n:
    print('nessuna soluzione')
else:
    print(m)
[Sergio] / $17$

Gianfranco
Supervisore del sito
Supervisore del sito
Messaggi: 1841
Iscritto il: ven mag 20, 2005 9:51 pm
Località: Sestri Levante
Contatta:

Re: [A25-51] Il problema dei due addendi

Messaggio da Gianfranco »

Quelo ha scritto:
dom lug 20, 2025 4:24 pm
"Scrivere un programmino" ha subito attirato la mia attenzione.

Vediamo 3 strategie:
1. La prima si basa sull'iterazione, cioè sul generare tutte le possibili coppie (combinazioni) e verificarne la somma (qui Python ci aiuta perché non dobbiamo scrivere il relativo codice)
2. La seconda consiste nel prelevare un elemento alla volta dalla lista e verificare se nel restante elenco è presente la differenza tra la somma obiettivo e l'elemento prelevato
3. La terza si limta a fare la scansione di tutte le somme con due cicli annidati
Grazie Quelo per il codice Python!
Io ho realizzato la strategia con due cicli annidati.
Incollo il programmino in DECIMAL BASIC.
Il programma genera una lista di numeri tutti diversi e la somma obiettivo, poi cerca le coppie.

Codice: Seleziona tutto

LET massimo=100
LET n=20
DIM lista(n)

RANDOMIZE 

!'Genera n numeri diversi a caso, compresi fra 1 e massimo
FOR i=1 TO n

!'Genera un nuovo numero diverso da tutti i precedenti
   DO
      LET nuovo_n=INT(RND*massimo+1)
      LET ok=1
      FOR k=1 TO i
         IF nuovo_n=lista(i) THEN LET ok=0
      NEXT k
      IF ok=1 THEN EXIT DO 
   LOOP
   !'Aggiunge il nuovo numero alla lista
    
   LET lista(i)= nuovo_n
   PRINT lista(i);
NEXT i

!'Genera la somma obiettivo
LET s_obiettivo=INT(RND*massimo+1)
PRINT ""
PRINT "Obiettivo";s_obiettivo

!'Cerca coppie di numeri che abbiano come somma la somma obiettivo
LET trovati=0
FOR a=1 TO n
   FOR b=a+1 TO n
      LET somma=lista(a)+lista(b)
      IF somma=s_obiettivo THEN
         LET trovati=trovati+1
         PRINT "L(";STR$(a);")=";lista(a);"L(";STR$(b);")=";lista(b);"Somma =";somma
      END IF
   NEXT b
NEXT a

PRINT "Trovati";trovati
END

Ecco un esempio di OUTPUT:
---
43 44 95 27 15 77 29 53 87 10 51 32 53 15 61 99 7 37 88 48
Obiettivo 85
L(8)= 53 L(12)= 32 Somma = 85
L(12)= 32 L(13)= 53 Somma = 85
L(18)= 37 L(20)= 48 Somma = 85
Trovati 3

---

Il problema è che se si vogliono trovare k numeri che abbiano una data somma, il sistema con i cicli annidati è da evitare.
Quindi, come si fa?
---
P.S.
Il professor Shiraizi Kazuo, autore del DECIMAL BASIC è andato in pensione (retired) diventando Professore Emerito. Credo che la manutenzione del suo BASIC si fermerà prima o poi.
Perciò penso di passare ad un altro linguaggio di scripting simile al BASIC (oltre all'ALGOL like di Maxima)
Mi piace LUA e lo sto usando da un po', con l'ambiente Zerobrane in Windows.
Mi piace anche R, ma è un'altra cosa.
Non riesco a usare Python per la faccenda che non ha le "parole" per chiudere i blocchi di codice. E' un linguaggio molto pratico ma questo suo aspetto non è nelle mie corde.
Secondo me l'indentazione deve derivare dal codice e non viceversa.
Voi che ne pensate di LUA?
Pace e bene a tutti.
Gianfranco

Quelo
Livello 8
Livello 8
Messaggi: 988
Iscritto il: ven giu 16, 2006 3:34 pm

Re: [A25-51] Il problema dei due addendi

Messaggio da Quelo »

Ciao Gianfranco,
non ho mai provato LUA (a dir la verità non ho mai usato altri linguaggi di programmazione oltre al BASIC, prima di passare a Python)
Ho consultato la guida di LUA per curiosità, ma mi sembra, a prima vista, un po' macchinoso.
Come in tutte le cose, bisognerebbe dedicargli un po' di tempo per poter dare un giudizio, ma io sono abbastanza pigro :wink:

Ma veniamo alla questione dei k addendi.
Con Python è presto detto, basta generare tutte le combinazioni di k elementi e il gioco è fatto.
Lo stesso discorso potrebbe essere trasportato in BASIC, ma richiederebbe la programmazione di una routine ricorsiva per le combinazioni e in questo caso la pirgizia è un ostacolo.
Così ho pensato di usare un numero binario di n bit per selezionare gli elementi dalla lista.
Faccio passare tutti i numeri binari da 2^k-1 (k volte 1) a 2^n-1 (n volte 1) e tengo solo quelli in cui l'1 compare k volte
Di questi verifico la somma

Codice: Seleziona tutto

LET m=100
LET n=20
LET k=7
DIM lista(n), temp(k), num(m)

RANDOMIZE 

MAT num=ZER

! riempie la lista con numeri casuali, tutti diversi 
LET s=0
FOR i=1 TO n
   DO 
      LET r=INT(RND*m+1)
   LOOP UNTIL num(r)=0
   LET num(r)=1
   LET lista(i)=r
   LET s=s+r
NEXT I

! genera la somma obiettivo come k volte la media della lista
LET s=INT(s*k/n)

MAT PRINT lista;
PRINT "Somma obiettivo"; s
PRINT

LET v=0
FOR i=2^k-1 TO 2^n-1
   LET t=0
   LET u=0
   MAT temp=ZER
   LET b$ = RIGHT$(REPEAT$("0",n) & BSTR$(i,2),n)
   FOR j=1 TO n
      IF mid$(b$,j,1)="1" THEN
         LET t=t+lista(j)
         LET u=u+1
         IF u>k THEN EXIT FOR
         LET temp(u)=lista(j)
      END IF
   NEXT J
   IF u=k AND t=s THEN
      MAT PRINT temp;
      LET v=v+1
   END IF
NEXT I
IF v>0 THEN
   PRINT "Trovati"; v
else 
   PRINT "Nessuna soluzione"
END if 
END
[Sergio] / $17$

Quelo
Livello 8
Livello 8
Messaggi: 988
Iscritto il: ven giu 16, 2006 3:34 pm

Re: [A25-51] Il problema dei due addendi

Messaggio da Quelo »

Ho scoperto che posso chiedere all'intelligenza artificiale (in questo caso Gemini di Google) di tradurre un codice da un linguaggio a un altro
Quindi se ho il programma che funziona in Decimal Basic posso ottenere il listato in LUA, senza conoscere quest'ultimo (e con la spiegazione di tutti gli adattamenti)
Ed ecco qua:

Codice: Seleziona tutto

-- Translation from Decimal BASIC to Lua

local m = 100
local n = 20
local k = 7

-- Initialize tables
local lista = {}
local temp = {}
local num = {}
for i = 1, m do
    num[i] = 0
end

-- Fill the lista table with unique random numbers
local s = 0
for i = 1, n do
    local r
    repeat
        r = math.random(m)
    until num[r] == 0
    num[r] = 1
    lista[i] = r
    s = s + r
end

-- Generate the target sum
local target_s = math.floor(s * k / n)

-- Print the list and target sum
local list_str = ""
for i = 1, n do
    list_str = list_str .. lista[i] .. " "
end
print(list_str)
print("Somma obiettivo: " .. target_s)

local v = 0
for i = 1, (2^n) - 1 do
    local t = 0
    local u = 0
    
    local is_valid_subset = true
    for j = 1, n do
        if ((i >> (j - 1)) % 2) == 1 then
            u = u + 1
            if u > k then
                is_valid_subset = false
                break
            end
            t = t + lista[j]
        end
    end

    if is_valid_subset and u == k and t == target_s then
        local solution = {}
        local count = 0
        for j = 1, n do
            if ((i >> (j - 1)) % 2) == 1 then
                count = count + 1
                solution[count] = lista[j]
            end
        end
        local solution_str = ""
        for _, val in ipairs(solution) do
            solution_str = solution_str .. val .. " "
        end
        print(solution_str)
        v = v + 1
    end
end

if v > 0 then
    print("Trovati " .. v)
else
    print("Nessuna soluzione")
end
Ultima modifica di Quelo il gio ago 28, 2025 8:19 pm, modificato 1 volta in totale.
[Sergio] / $17$

Quelo
Livello 8
Livello 8
Messaggi: 988
Iscritto il: ven giu 16, 2006 3:34 pm

Re: [A25-51] Il problema dei due addendi

Messaggio da Quelo »

Ho approfondito la questione ed elaborato alcune strategie.
Partiamo dal presupposto che nessun numero uguale o superiore alla somma obiettivo può essere addendo, quindi un primo passaggio potrebbe essere quello di filtrare la lista lasciando solo i numeri inferiori alla somma.
Dopo questa operazione avremo una lista di $n$ elementi, nella quale sono contenute $m$ soluzioni, con $m \geq 0$

La prima strategia è quella di controllare tutte le somme possibili, cioè confrontare ogni elemento della lista con ogni altro elemento. Questo algoritmo richiede $q=n(n-1)$ passaggi ed è il meno efficiente
Si può facilmente ottimizzare verificando solo le somme di un elemento con quelli successivi. La complessità diventa $\displaystyle q=\frac{n(n-1)}{2}$

Codice: Seleziona tutto

LET m=0
LET q=0
FOR i=1 TO n-1
   FOR j=i+1 TO n
      IF lista(i)+lista(j)=somma THEN
         LET m=m+1
         PRINT lista(i);lista(j)
      END IF
      LET q=q+1
   NEXT J
NEXT I

Questo equivale di fatto a controllare tutte le combinazioni di $2$ elementi su $n$ che richiede appunto $\displaystyle q=\binom{n}{2}$ passaggi
Miglioramenti si possono ottenere eliminando dalla lista le soluzioni già trovate, la complessità dell’algoritmo in questo caso è di circa $\displaystyle q=\frac{(n-m)(n-m-1)}{2}$.
Purtroppo Decimal Basic non ha una funzione dedicata per questo e implementare una routine rallenterebbe l’algoritmo in modo rilevante.

A questo punto possiamo fare un'ulteriore considerazione: essendo solo 2 addendi, uno dei due deve essere minore della metà della somma obiettivo e l’altro maggiore.
Possiamo quindi creare 2 nuove liste, una con i numeri inferiori e l’altra con quelli superiori e per ogni numero della prima verificare le somme con quelli della seconda. Nel peggiore dei casi la complessità si riduce comunque a $\displaystyle q=\frac{n^2}{4}$

Codice: Seleziona tutto

DIM a(n),b(n)
LET ai=0
LET bi=0

FOR i=1 TO n
   IF lista(i)<somma/2 THEN 
      LET ai=ai+1
      LET a(ai)=lista(i)
   ELSEIF lista(i)>somma/2 THEN
      LET bi=bi+1
      LET b(bi)=lista(i)
   END IF
NEXT I

LET m=0
LET q=0
FOR i=1 TO ai
   FOR j=1 TO bi
      IF a(i)+b(j)=somma THEN
         LET m=m+1
         PRINT a(i);b(j)
      END IF
      LET q=q+1
   NEXT J
NEXT I
In ultimo potremmo usare un metodo estremamente rapido ma che presuppone che la lista sia in ordine. In questo caso possiamo infatti procedere in questo modo, controlliamo la somma del primo e dell’ultimo numero, se è minore dell’obiettivo, scartiamo il primo, se è maggiore, scartiamo l’ultimo e se è uguale li scartiamo tutti e due.

Codice: Seleziona tutto

LET m=0
LET q=0
LET i0 = 1
LET i1 = n
DO
   IF lista(i0)+lista(i1)<somma THEN 
      LET i0=i0+1
      LET q=q+1
   ELSEIF lista(i0)+lista(i1)>somma THEN 
      LET i1=i1-1
      LET q=q+1
   ELSE
      LET m=m+1
      PRINT lista(i0);lista(i1) 
      LET i0=i0+1
      LET i1=i1-1
      LET q=q+1
   END IF
LOOP UNTIL i1-i0<1
La complessità dell’algoritmo è $n-m-1$
E’ talmente veloce che ci possiamo permettere anche l’algoritmo di ordinamento della lista
[Sergio] / $17$

Quelo
Livello 8
Livello 8
Messaggi: 988
Iscritto il: ven giu 16, 2006 3:34 pm

Re: [A25-51] Il problema dei due addendi

Messaggio da Quelo »

Vediamo ora come affrontare il problema dei 3 addendi e quello dei 4 addendi, senza scomodare le combinazioni.
Come sappiamo le combinazioni di $3$ elementi su $n$, con $n$ abbastanza grande, sono nell’ordine di $\displaystyle q=\frac{n^3}{6}$ e quelle di $4$ sono $\displaystyle q=\frac{n^4}{24}$
Partendo da una lista ordinata, con il metodo ad eliminazione possiamo ridurre la complessità a circa $\displaystyle q=\frac{n^2}{3}$ per 3 addendi e circa $\displaystyle q=\frac{n^3}{8}$ per 4 addendi

3 addendi
Il minore dei 3 addendi deve essere inferiore a un terzo della somma, questo ci permette di considerare solo una parte della lista per il primo addendo.
Partendo dal numero più piccolo a salire, per ogni numero della lista applichiamo il metodo ad eliminazione per i numeri superiori, che saranno progressivamente sempre meno

Codice: Seleziona tutto

   LET m=0
   LET q=0
   FOR j=1 TO n-k+1
      IF lista(j)>somma/3 THEN EXIT FOR 
      LET i0=j+1
      LET i1=n
      LET dif=somma-lista(j)
      DO
         IF lista(i0)+lista(i1)<dif THEN 
            LET i0=i0+1
            LET q=q+1
         ELSEIF lista(i0)+lista(i1)>dif THEN 
            LET i1=i1-1
            LET q=q+1
         ELSE
            LET m=m+1
            PRINT lista(j);lista(i0);lista(i1) 
            LET i0=i0+1
            LET i1=i1-1
            LET q=q+1
         END IF
      LOOP UNTIL i1-i0<1
   NEXT j
4 addendi
Per 4 addendi il principio è lo stesso, infatti l’addendo minore deve essere inferiore a un quarto della somma, mentre la somma dei primi due deve essere minore della metà della somma obiettivo

Codice: Seleziona tutto

   LET m=0
   LET q=0
   FOR i=1 TO n-k+1
      IF lista(i)>somma/4 THEN EXIT FOR
      FOR j=i+1 TO n-k+2
         IF lista(i)+lista(j)>somma/2 THEN EXIT FOR 
         LET i0=j+1
         LET i1=n
         LET dif=somma-lista(i)-lista(j)
         DO
            IF lista(i0)+lista(i1)<dif THEN 
               LET i0=i0+1
               LET q=q+1
            ELSEIF lista(i0)+lista(i1)>dif THEN 
               LET i1=i1-1
               LET q=q+1
            ELSE
               LET m=m+1
               PRINT lista(i);lista(j);lista(i0);lista(i1) 
               LET i0=i0+1
               LET i1=i1-1
               LET q=q+1
            END IF
         LOOP UNTIL i1-i0<1
      NEXT j
   NEXT i
Per verificare che i due metodi funzionassero correttamente, e per gestire gli addendi maggiori di 4, ho rielaborato l’esempio di routine per le combinazioni COMBINAT.BAS per adattarlo allo scopo.
Lascio qui il listato completo per 2, 3, 4 e maggiore di 4 addendi

Codice: Seleziona tutto

DECLARE EXTERNAL SUB combs

LET n=20                !numero di elementi
LET t=5*n               !limite superiore dei valori
LET k=2                 !numero di addendi

DIM lista(n), num(t)

RANDOMIZE 

MAT num=ZER
LET x = 0

! riempie la lista con numeri casuali, tutti diversi 
LET s=0
FOR i=1 TO n
   DO 
      LET r=INT(RND*t+1)
   LOOP UNTIL num(r)=0
   LET num(r)=1
   LET lista(i)=r
   LET s=s+r
   IF r>x THEN LET x=r
NEXT I

! genera la somma obiettivo superiore al maggiore della lista
LET somma=INT(s*k/n)
DO WHILE somma<x
   LET somma=INT(somma*(RND+1))  
LOOP

IF n<=100 THEN MAT PRINT lista;
PRINT "Somma obiettivo"; somma
PRINT

SELECT CASE k
CASE 2

! metodo a scansione progressiva
   LET tempo = TIME
    
   LET m=0
   LET q=0
   FOR i=1 TO n-1
      FOR j=i+1 TO n
         IF lista(i)+lista(j)=somma THEN
            LET m=m+1
            PRINT lista(i);lista(j)
         END IF
         LET q=q+1
      NEXT J
   NEXT I
    
   IF m>0 THEN
      PRINT "Trovati"; m; " q ="; q
   ELSE 
      PRINT "Nessuna soluzione"; " q ="; q
   END if 
   PRINT "Scansoine prog. tempo: "; TIME-tempo
    
! metodo a separazione
   LET tempo = TIME
    
   DIM a(n),b(n)
   LET ai=0
   LET bi=0
    
   FOR i=1 TO n
      IF lista(i)<somma/2 THEN 
         LET ai=ai+1
         LET a(ai)=lista(i)
      ELSEIF lista(i)>somma/2 THEN
         LET bi=bi+1
         LET b(bi)=lista(i)
      END IF
   NEXT I
    
   LET m=0
   LET q=0
   FOR i=1 TO ai
      FOR j=1 TO bi
         IF a(i)+b(j)=somma THEN
            LET m=m+1
            PRINT a(i);b(j)
         END IF
         LET q=q+1
      NEXT J
   NEXT I
    
   IF m>0 THEN
      PRINT "Trovati"; m; " q ="; q
   ELSE 
      PRINT "Nessuna soluzione"; " q ="; q
   END if 
   PRINT "Separazione tempo: "; TIME-tempo
    
! metodo a eliminazione
   LET tempo = TIME
    
   LET c=0
   FOR i=1 TO t
      IF num(i)>0 THEN 
         LET c=c+1
         LET lista(c)=i
      END IF
   NEXT i
    
   LET m=0
   LET q=0
   LET i0 = 1
   LET i1 = n
   DO
      IF lista(i0)+lista(i1)<somma THEN 
         LET i0=i0+1
         LET q=q+1
      ELSEIF lista(i0)+lista(i1)>somma THEN 
         LET i1=i1-1
         LET q=q+1
      ELSE
         LET m=m+1
         PRINT lista(i0);lista(i1) 
         LET i0=i0+1
         LET i1=i1-1
         LET q=q+1
      END IF
   LOOP UNTIL i1-i0<1
    
   IF m>0 THEN
      PRINT "Trovati"; m; " q ="; q
   ELSE 
      PRINT "Nessuna soluzione"; " q ="; q
   END if 
   PRINT "Eliminazione tempo: "; TIME-tempo
    
CASE 3

   LET tempo = TIME

! ordina la lista
   LET c=0
   FOR i=1 TO t
      IF num(i)>0 THEN 
         LET c=c+1
         LET lista(c)=i
      END IF
   NEXT i
    
   IF n<=100 THEN MAT PRINT lista;
    
   LET m=0
   LET q=0
   FOR j=1 TO n-k+1
      IF lista(j)>somma/3 THEN EXIT FOR 
      LET i0=j+1
      LET i1=n
      LET dif=somma-lista(j)
      DO
         IF lista(i0)+lista(i1)<dif THEN 
            LET i0=i0+1
            LET q=q+1
         ELSEIF lista(i0)+lista(i1)>dif THEN 
            LET i1=i1-1
            LET q=q+1
         ELSE
            LET m=m+1
            PRINT lista(j);lista(i0);lista(i1) 
            LET i0=i0+1
            LET i1=i1-1
            LET q=q+1
         END IF
      LOOP UNTIL i1-i0<1
   NEXT j
    
   IF m>0 THEN
      PRINT "Trovati"; m; " q ="; q
   ELSE 
      PRINT "Nessuna soluzione"; " q ="; q
   END if 
   PRINT "Eliminazione tempo: "; TIME-tempo
    
CASE 4

   LET tempo = TIME

!odrina la lista    
   LET c=0
   FOR i=1 TO t
      IF num(i)>0 THEN 
         LET c=c+1
         LET lista(c)=i
      END IF
   NEXT i
    
   IF n<=100 THEN MAT PRINT lista;
    
   LET m=0
   LET q=0
   FOR i=1 TO n-k+1
      IF lista(i)>somma/4 THEN EXIT FOR
      FOR j=i+1 TO n-k+2
         IF lista(i)+lista(j)>somma/2 THEN EXIT FOR 
         LET i0=j+1
         LET i1=n
         LET dif=somma-lista(i)-lista(j)
         DO
            IF lista(i0)+lista(i1)<dif THEN 
               LET i0=i0+1
               LET q=q+1
            ELSEIF lista(i0)+lista(i1)>dif THEN 
               LET i1=i1-1
               LET q=q+1
            ELSE
               LET m=m+1
               PRINT lista(i);lista(j);lista(i0);lista(i1) 
               LET i0=i0+1
               LET i1=i1-1
               LET q=q+1
            END IF
         LOOP UNTIL i1-i0<1
      NEXT j
   NEXT i
    
   IF m>0 THEN
      PRINT "Trovati"; m; " q ="; q
   ELSE 
      PRINT "Nessuna soluzione"; " q ="; q
   END if 
   PRINT "Eliminazione tempo: "; TIME-tempo
    
CASE ELSE
 
   LET tempo = TIME
    
   LET p=COMB(n,k)
   DIM u(n), v(p,k)
    
   MAT u=ZER(n)
   CALL combs(u,v,1,1,k)
    
   LET m=0
   LET q=0
   FOR i=1 TO p
      LET s=0
      FOR j=1 TO k 
         LET s=s+lista(v(i,j))
      NEXT j
      IF s=somma THEN 
         FOR j=1 TO k 
            PRINT lista(v(i,j));
         NEXT j
         LET m=m+1
         print
      END IF
      LET q=q+1
   NEXT i
    
   IF m>0 THEN
      PRINT "Trovati"; m; " q ="; q
   ELSE 
      PRINT "Nessuna soluzione"; " q ="; q
   END if 
   PRINT "Combinazione tempo: "; TIME-tempo
    
END SELECT
END

EXTERNAL SUB combs(a(),b(,),c,k,r)
IF r=0 THEN 
   LET d=0
   FOR i=1 TO UBOUND(a)
      IF a(i)=1 THEN
         LET d=d+1 
         LET b(c,d)=i
      END IF
   NEXT i
   LET c=c+1
ELSE
   FOR i=k TO UBOUND(a)-r+1
      LET a(i)=1
      CALL combs(a,b,c,i+1,r-1)
      LET a(i)=0
   NEXT i
END IF 
END SUB
Ultima modifica di Quelo il sab set 20, 2025 5:50 pm, modificato 1 volta in totale.
[Sergio] / $17$

Quelo
Livello 8
Livello 8
Messaggi: 988
Iscritto il: ven giu 16, 2006 3:34 pm

Re: [A25-51] Il problema dei due addendi

Messaggio da Quelo »

Per il problema dei due addendi, ho sviluppato un sistema ancora più veloce, che dimezza i tempi del metodo a eliminazione

Partiamo da una lista non ordinata e applichiamo il metodo di ordinamento a conteggio.
Creiamo un secondo array di lunghezza pari a valore massimo che può essere presente nella lista (nel nostro caso 5 volte la lunghezza della lista)
Per ogni valore della lista, inserisco $1$ nella relativa posizione della seconda lista (una sorta di indicizzazione)
Contemporaneamente compilo una terza lista con tutti i valori inferiori alla metà della somma (non importa che siano in ordine)
Fatto questo ci basterà verificare, per ogni elemento della terza lista, se la differenza con la somma è presente nella lista indicizzata.

Codice: Seleziona tutto

   ! metodo a indicizzazione
   LET tempo = TIME
    
   DIM lista2(n)
   LET c=0
   LET s2=somma/2
   FOR i=1 TO n
      IF lista(i)<s2 THEN 
         LET c=c+1
         LET lista2(c)=lista(i)
      END IF
   NEXT i
    
    
   LET m=0
   LET q=0
   FOR i=1 TO c
      LET d = somma-lista2(i)
      IF d < t THEN
         IF num(d)=1 THEN 
            PRINT lista2(i);somma-lista2(i)
            LET m=m+1
         END IF
      END IF
      LET q=q+1
   NEXT I
    
   IF m>0 THEN
      PRINT "Trovati"; m; " q ="; q
   ELSE 
      PRINT "Nessuna soluzione"; " q ="; q
   END if 
   PRINT "Indicizzazione tempo: "; TIME-tempo
[Sergio] / $17$

Rispondi