domenica 21 ottobre 2018

Quesito con la Susi n. 954

Questo è un po' come altri quesiti in cui la difficoltà sta tutta nel trasformare le affermazioni dei personaggi in equazioni. Ne risulta un sistema di equazioni la cui soluzione è la soluzione del quesito.

I linguaggi di programmazione usabili per risolvere “chiavi in mano” questo tipo di problemi con il minimo sforzo sono Maxima, Prolog, Metafont… Tutti già usati. In alternativa c'è il solito metodo rozzo che usa la forza bruta: assegna alle variabili “tutti” i valori possibili e verifica per quali le equazioni sono verificate. Questo secondo approccio ci fa scrivere dei programmi che sono essenzialmente sempre gli stessi a prescindere dal linguaggio (persino cambiando il paradigma non abbiamo grosse differenze).

La tecnica per questo tipo di problemi è sempre la stessa:

  1. date le variabili v1, v2, v3, …, vn (cioè in breve $\vec{v}$)
  2. date le condizioni $C_1(\vec{v})$, $C_2(\vec{v})$, …, $C_m(\vec{v})$
  3. provare “tutti” i valori di v1, …, vn fino a trovare quelli che soddisfano tutte le condizioni (se m > n ce ne sono troppe, se m < n ce ne sono troppo poche…)

L'unico trucco da applicare è ridurre quel “tutti” a un numero finito e che possa essere “provato” in tempi accettabili. Vista la natura dei quesiti con la Susi non dobbiamo temere di trovarci di fronte a casi in cui sia necessaria particolare attenzione.

A: Nei nostri portafogli abbiamo in tutti 150 euro

A + B + G = 150

B: Ma adesso dividiamo il conto in tre parti uguali e ognuno paga la stessa cifra

(C = 3c)

A: Adesso io ho quanto tu, Berto, avevi prima di pagare

A − C/3 = B

B: E io ho tanti soldi quanti ne avevi tu, Gianni

B − C/3 = G

G: e io mi ritrovo con la metà di quanto prima aveva Aldo

G − C/3 = A/2

Mettiamo queste equazioni in Maxima e troviamo C (in realtà ne bastano 3, visto che C si può riscrivere in termini di A, B e G). È l'immagine del post (dalla quale si evince che ho usato maxima e non xmaxima o wxmaxima). Non molto entusiasmante, e del resto scrivere un programma per risolvere un sistema di equazioni cambierebbe un po' lo spirito di questa serie… Ma, come già fatto in altre occasioni, abbiamo un approccio più rozzo, più inefficiente e più stupido: provarle tutte finché non troviamo quella che soddisfa le equazioni!

package main

import "fmt"

func e1(a, b, g float32) bool {
        return a + b + g == 150.0;
}

func c(a, b, g float32) float32 {
        return 150.0 - a/2 - b - g;
}

func e2(a, b, g float32) bool {
        return a - c(a, b, g)/3 == b;
}

func e3(a, b, g float32) bool {
        return b - c(a, b, g)/3.0 == g;
}

func inc(a []float32, lim float32) {
        for i := 0; i < len(a); i++ {
                a[i]++;
                if a[i] <= lim {
                        break
                } else {
                        a[i] = 0
                }
        }
}

func is_zero(a []float32) bool {
        for _, e := range a {
                if e != 0.0 {
                        return false
                }
        }
        return true;
}


func main() {
        v := []float32{150.0, 0.0, 0.0}

        for !is_zero(v) {
                if e1(v[0], v[1], v[2]) &&
                        e2(v[0], v[1], v[2]) &&
                        e3(v[0], v[1], v[2]) {
                        fmt.Println(c(v[0], v[1], v[2]));
                        break
                }
                inc(v, 150.0)
        }
}

C'è già una piccola “ottimizzazione” qui: infatti non sono partito da {0.0, 0.0, 0.0} perché è palese che violi la prima equazione (e inoltre viene considerato come valore speciale per la fine del ciclo). La soluzione viene trovata dopo aver provato 919501 valori.

Nessun commento:

Posta un commento

Sii educato, costruisci con cura le frasi, rifletti prima di pubblicare, evita parolacce e offese dirette, non uscire dal tema, cerca di non omettere la punteggiatura, evita errori ortografici, rileggi quel che hai scritto.