tappe

Transcript

tappe
Prova di Laboratorio di Programmazione
26 febbraio 2015
ATTENZIONE: Non è possibile usare le classi del package prog.io del libro di testo. Oltre ai metodi richiesti
in ciascuna classe, è opportuno implementare altri metodi che si ritengono utili per svolgere l’esercizio nel modo più
corretto ed elegante, per esempio il metodo toString() e, quando necessario, i metodi di accesso ai campi. Le
operazioni di stampa vanno effettuate esclusivamente nella classe che definisce il metodo main().
Lo scopo del tema è di modellare il viaggio di un’auto che ha un’autonomia (intesa come massima quantità di benzina
che il suo serbatoio può contenere) che gli permette di percorrere k chilometri. All’inizio, alla fine del percorso e nelle
tappe intermedie sono presenti dei distributori di benzina.
Esercizio 1
Si implementino le seguenti classi.
Classe Posizione
Un’istanza della classe Posizione è descritta da due attributi, rappresentati da numeri reali, che corrispondono alle
coordinate x e y di un punto su un piano cartesiano. La classe implementa il metodo:
public static double distanza(Posizione p1,Posizione p2) che calcola la distanza euclidea
tra due posizioni.
Classe Distributore
Un’istanza della classe Distributore rappresenta un distributore, ed è caratterizzato da:
• posizione (di tipo Posizione);
• disponibilita (di tipo double).
L’attributo disponibilita contiene la disponibilità di benzina, per semplicità espressa dal numero di chilometri
che possono essere percorsi da un’auto rifornita con tutto il carburante disponibile nel distributore.
La classe implementa i metodi:
• public static double calcolaDistanza(Distributore start, Distributore end) :
calcola la distanza tra due distributori passati come argomento del metodo.
• public boolean erogaBenzina(double km): prova a erogare una quantità di benzina che permette
all’auto di percorrere km chilometri. Restituisce true se l’operazione è andata a buon fine (e in tal caso riduce
la disponibilità), false altrimenti.
Classe AutoNavigatore.
Un oggetto della classe AutoNavigatore rappresenta un’auto con un semplicissimo navigatore; il navigatore permette di svolgere un percorso tra due distributori, memorizzandone le posizioni e la lunghezza del percorso effettuato.
La classe ha due attributi:
• ArrayList<Distributore> listaDistributori: è una lista di N distributori che possono essere
inclusi in un eventuale percorso. listaDistributori viene passata come argomento del costruttore.
• double autonomia è l’autonomia dell’auto (ovvero, il parametro k citato nella introduzione: il serbatoio
dell’auto può contenere al massimo una quantità di benzina che le permettere di percorrere un numero di chilometri pari al valore contenuto nella variabile autonomia). Anche il valore dell’autonomia dell’auto viene passato
come argomento del costruttore.
1
Il calcolo di un percorso tra alcuni distributori in listaDistributori viene eseguito dal metodo
• public ArrayList<Distributore> percorri(ArrayList<Integer> listaTappe): riceve come argomento una lista di interi che rappresentano gli indici dei distributori in listaDistributori.
I distributori indicati sono le tappe consecutive del percorso da percorrere.
Più precisamente, si suppone che l’auto parta dal primo distributore trovato in listaTappe, che chiameremo
A, e che l’auto abbia inzialmente 0 km di benzina nel serbatoio. Se il secondo distributore in listaTappe,
che chiameremo B, dista d km da A, l’auto deve rifornirsi di una quantità di benzina pari a d km, in modo da
raggiungere cosı̀ B. Ciò è possibile solo se d ≤autonomia dell’auto (ovvero se il serbatoio dell’auto è abbastanza capiente, in modo da contenere cosı̀ la benzina necessaria per percorrere d km) e se il distributore A ha
ancora una disponibilità di benzina sufficiente per erogare d km (ovvero se d ≤disponibilita). Raggiunto
B, il navigatore dovrà applicare gli stessi criteri per valutare se l’auto può raggiungere la terza tappa in lista, e
cosı̀ via. Se uno dei criteri precedentemente descritti non è valido, il percorso va interrotto. Il metodo restituisce
la lista dei distributori visitati, che può essere più corta della lista delle tappe da effettuare se il percorso viene
interrotto (per un esempio concreto del metodo, leggete il prossimo paragrafo).
• public static double lunghezzaPercorso(ArrayList<Distributore> listaTappe):
riceve come argomento una lista di distributori, e calcola la lunghezza totale del percorso che li collega.
Scrivere un programma Prog1 che riceve da linea di comando il parametro N che rappresenta il numero di distributori tra cui possono essere calcolati i vari percorsi, e il parametro k che rappresenta l’autonomia dell’auto. Il
programma inizialmente legge da standard input N righe che descrivono N distributori. Ogni riga ha il formato:
coordx coordy disponibilita
Tali valori sono le coordinate delle posizioni di un distributore e il carburante inizialmente presente in quel distributore.
Leggete questi valori usando Scanner.nextDouble().
Successivamente il programma legge una lista di interi che rappresentano le tappe del percorso da effettuare e di cui
calcolare la lunghezza. Leggeteli utilizzando Scanner.nextInt() e usate Scanner.hasNext() per rilevare
la fine del file. Avendo eseguito tali passi il programma cerca di effettuare il percorso stampando poi a video un
messaggio di notifica riguardo l’esito del percorso, il numero di tappe effettivamente raggiunte, la sua lunghezza e la
distanze media tra le coppie di tappe consecutive (sia che il percorso sia stato interrotto sia che esso sia stato terminato).
Non è necessario fare controlli sulla correttezza dell’input. Non vanno fatte assunzioni sul numero di righe in input.
L’input va letto da standard input e non da file. Per testare il programma, consigliamo di utilizzare la redirezione
fornita dalla shell (si vedano gli esempio sotto).
Esempio di funzionamento del metodo AutoNavigatore.percorri()
Supponiamo che l’argomento del metodo AutoNavigatore.percorri() sia il percorso con le seguenti tappe:
• partire dal distributore A, contenente 75 km di benzina;
• arrivare al distributore B, distante 25 km da A e contenente 30 km di benzina;
• arrivare al distributore C, distante 30 km da B e contenente 60 km di benzina;
• arrivare al distributore A (lo stesso da cui il percorso parte), distante 50 km da C;
• arrivare al distributore D, distante 15 km da A e contenente 15 km di benzina;
• terminare nel distributore B, distante 20 km da D.
2
Si noti che in realtà i distributori sono descritti da indici nella lista complessiva dei distributori. Questo esempio usa
delle lettere per semplicità.
Se l’auto avesse una autonomia di 30 km potrebbe rifornirsi con 25 km di benzina (lasciandone quindi 50 in A) e
raggiungere B. Da qui potrebbe riempire tutto il serbatoio con i 30 km di benzina necessari a raggiungere C, lasciando
0 km di benzina in B. A questo punto il percorso si interromperebbe perchè l’auto ha una autonomia (30 km) minore
della distanza dalla prossima tappa in A (50 km).
Se l’auto avesse un’autonomia di 60 km potrebbe partire da A, arrivare in B, arrivare in C, rifornirsi e lasciare 10 km
di benzina in C, tornare in A e rifornirsi dei 15 km necessari ad andare in D (lasciandone 35 in A). A questo punto il
percorso si interromperebbe perché la distanza di B da D (20 km) è maggiore della quantità di benzina disponibile in
D (15 km).
Supponendo infine che l’auto avesse una autonomia di 60 km e che in D ci fossero 30 km di benzina, l’auto potrebbe
terminare il percorso in B.
Nel primo caso il percorso A → B → C sarebbe lungo 25 + 30 = 55 km (distanza media tra tappe consecutive:
27, 5 km).
Nel secondo caso il percorso A → B → C → A → D sarebbe lungo 25 + 30 + 50 + 15 = 120 km (distanza media
tra tappe consecutive: 30 km).
Nel terzo caso il percorso A → B → C → A → D → B sarebbe lungo 25 + 30 + 50 + 15 + 20 = 140 km (distanza
media tra tappe consecutive: 28 km).
Esempio
Il file in.txt contiene le righe seguenti:
2.5 3.0 100
1.2 4.0 50
0.4 10.0 200
20.0 20.0 30
2.0 3.0 10
5.0 7.0 20
10.0 11.0 10
0
1
2
3
0
4
2
Esempi di esecuzione:
> java Prog1 7 30 <in.txt
Il percorso è stato completato
Numero di tappe percorse: 7
Distanza totale: 61.775131415932606
Distanza media: 10.295855235988768
> java Prog1 7 20 <in.txt
Il percorso non è stato completato
Numero di tappe percorse: 3
Distanza totale: 7.693220326854295
Distanza media: 3.8466101634271475
3
> java Prog1 7 5 <in.txt
Il percorso non è stato completato
Numero di tappe percorse: 2
Distanza totale: 1.6401219466856727
Distanza media: 1.6401219466856727
Esercizio 2
Si realizzi la seguente classe che eredita da AutoNavigatore:
Classe AutoNavigatoreIntelligente.
Gli oggetti della classe sono istanze di AutoNavigatore dotate di un metodo aggiuntivo
public ArrayList<Distributore> calcolaMigliore(): cerca di calcolare un buon percorso tra il
primo e l’ultimo distributore della lista. Per fare ciò, il navigatore sceglie ad ogni passo la prossima tappa tramite
il seguente algoritmo. Quando l’auto è in un distributore, che chiameremo A, la prossima tappa viene scelta tra
tutti i distributori raggiungibili, cioè a distanza minore o uguale ad autonomia e minore o uguale alla quantità di
carburante residuo in A. Tra tutti i distributori raggiungibili che non sono ancora stati utilizzati nel percorso, viene
scelto il distributore più vicino all’ultimo. Se l’ultimo è il distributore più vicino, viene aggiunto al percorso e il
metodo termina. Se da A non ci sono distributori che rispettano i criteri precedentemente descritti il metodo termina
il calcolo del percorso. In ogni caso, il percorso calcolato viene restituito come risultato.
Scrivere un programma Prog2 che riceve da linea di comando il parametro N che rappresenta il numero di distributori
tra cui possono essere calcolati i vari percorsi, e il parametro k che rappresenta l’autonomia dell’auto. Usando gli stessi
formati di riga descritti per Prog1, Prog2 legge da standard input una lista di N righe che descrivono N distributori.
Il programma quindi cerca di calcolare il percorso migliore tra il primo e l’ultimo distributore. Sia che il percorso risulti
interrotto o che si riesca a raggiungere l’ultimo distributore, il programma stampa il numero di tappe, la lunghezza del
percorso pianificato e la distanza media tra due distributori.
Non è necessario fare controlli sulla correttezza dell’input. L’input va letto da standard input e non da file. Per
testare il programma, consigliamo di utilizzare la redirezione fornita da shell (si veda l’esempio sotto).
Esempio
Si noti che le righe di in.txt che descrivono le tappe non vengono lette da Prog2.
> java Prog2 7 30 <in.txt
Il percorso è stato completato
Numero di tappe percorse: 2
Distanza totale: 10.965856099730654
Distanza media: 10.965856099730654
> java Prog2 7 10 <in.txt
Il percorso è stato completato
Numero di tappe percorse: 3
Distanza totale: 11.12011480346115
Distanza media: 5.560057401730575
> java Prog2 7 5 <in.txt
Il percorso non è stato completato
Numero di tappe percorse: 4
Distanza totale: 10.839102788278952
Distanza media: 3.613034262759651
4
Istruzioni per la consegna
Consegnare soltanto i file sorgenti (non i file .class): come un unico file compresso creato col comando
zip nome_cognome
*.java
Eseguire l’upload del file all’indirizzo upload.di.unimi.it.
Non consegnate file che non compilano. Se decidete di ritirarvi create (e consegnate tramite il metodo di upload) un
file di testo dal nome ritirato.txt.
5