Scaricare la presentazione
La presentazione è in caricamento. Aspetta per favore
PubblicatoMassimo Marra Modificato 11 anni fa
1
TESTI UFFICIALI MEYERS R.A. PASCAL Prentice Hall FIORENTINO G., LAGANA M.R., ROMANI F., TURINI F. PASCAL LABORATORIO DI PROGRAMMAZIONE McGraw-Hill
2
ESAMI FEBBRAIO 2001 - MOD. A
3
1.Sia dato un file di testo riguardante un insieme di soggetti di cui è fornito il cognome seguito dalla nazionalità e dalla data di nascita, giorno mese anno. Nel primo rigo sono indicati e nome e cognome dellautore della registrazione e il numero di soggetti registrati. Il file sarà perciò così composto: tipo datoesempio rigo stringa, integer carlo bruni^ 76 1 stringa stringa^ integer integer integer rossi italiano^22 12 19302 stringa stringa^ integer integer integer smith inglese^ 28 9 19903 …………………………………………………………………………………………… ……………………………………………………………………………………………. Leggere il file mostrando a video i nomi ordinati per nazionalità e con la data di nascita. ESAMI MOD. A
4
PROGRAM Esercizio1(output,Client); CONST LunMax=40; MassimoCli=100; TYPE StringaNome=STRING[LunMax]; AnagraficaRecord=RECORD Cognome, Nome:StringaNome; END; DataRecord=RECORD Giorno, Mese, Anno:integer; END; ClienteRecord=RECORD CognCli:StringaNome; Nazione:StringaNome; Nascita:DataRecord; END; RappresentanteRecord=RECORD Anagrafe:AnagraficaRecord; NumeroCli:integer; END; IndiceTipo=0.. MassimoCli; CliArray=ARRAY[IndiceTipo] OF ClienteRecord; VAR Clienti:CliArray; IndiceCli:IndiceTipo; ClientiFile:text; UnCliente: ClienteRecord; UnRappresentante: RappresentanteRecord; DataRecord GiornoMese Anno AnagraficaRecord CognomeNome RappresentanteRecord Anagrafe Numero ClienteRecord CognCliNazione Nascita BEGIN assign(ClientiFile,'C:\Modapr\test1.TXT'); reset(ClientiFile); LeggiRappresentante(ClientiFile, IndiceCli); readln; OrdinaClienti(IndiceCli,Clienti, ClientiFile); MostraRisultati(Clienti,IndiceCli); readln END.
5
ApriFile ClientiFile LeggiRappresentante IndiceCli LeggiParola CognomeSentinella LeggiParola Nome Sentinella ClientiFile LeggiParola GiornoSent ClientiFile LeggiParola CognCliSent ClientiFile MostraRisultati IndiceCli Clienti OrdinaClienti IndiceCli Clienti ClientiFile CostruisciRecordCliente IndiceCli ClientiFile Clienti[I] LeggiParola Sent ClientiFile Nazione LeggiParola Sent ClientiFile Mese LeggiParola Sent ClientiFile Anno BEGIN assign(ClientiFile,'C:\Modapr\test1.TXT'); reset(ClientiFile); LeggiRappresentante(ClientiFile, IndiceCli); readln; OrdinaClienti(IndiceCli,Clienti, ClientiFile); MostraRisultati(Clienti,IndiceCli); readln END.
6
PROCEDURE LeggiParola(Sentinella:char;VAR Parola:StringaNome;VAR Clienti:text); VAR Carattere:char; BEGIN Parola:=''; read(Clienti,Carattere); WHILE (Carattere<>Sentinella) DO BEGIN Parola:=Parola+Carattere; read( Clienti,Carattere) END;
7
PROCEDURE CostruisciRecordCliente(UnCliente:ClienteRecord;VAR ClientiFile:text); BEGIN WITH UnCliente, Nascita DO BEGIN LeggiParola(' ',CognCli, ClientiFile); LeggiParola('^',Nazione, ClientiFile); read(ClientiFile,Giorno); read(ClientiFile,Mese); read(ClientiFile,Anno); readln(ClientiFile); writeln(' Cliente ',CognCli,' ',' Nazionalita'' ',Nazione); writeln(' Nato il ',Giorno,'/',Mese,'/',Anno); writeln END END; PROCEDURE LeggiRappresentante (VAR ClientiFile:text; VAR IndiceCli1:IndiceTipo); VAR UnRappresentante: RappresentanteRecord; BEGIN WITH UnRappresentante, Anagrafe DO BEGIN LeggiParola(' ',Cognome, ClientiFile); LeggiParola('^',Nome, ClientiFile); read(ClientiFile,IndiceCli1); readln(ClientiFile); writeln('Rappresentante ',Cognome,' ',Nome,'N. Clienti',IndiceCli); END END;
8
PROCEDURE Scambia(VAR Ch1,Ch2: StringaNome); VAR Temp: StringaNome; BEGIN Temp:=Ch1; Ch1:=Ch2; Ch2:=Temp END; PROCEDURE Ordina(VAR Clienti:CliArray; IndiceCli:IndiceTipo); VAR Ordinato, Indice: IndiceTipo; BEGIN WITH UnCliente DO FOR Ordinato:=1 TO IndiceCli DO FOR Indice:= IndiceCli DOWNTO Ordinato DO IF Clienti[Indice].Nazione > Clienti[Indice+1].Nazione THEN Scambia(Clienti[Indice].Nazione,Clienti[Indice+1].Nazione); END;
9
PROCEDURE OrdinaClienti(VAR IndiceCli:IndiceTipo;VAR Clienti:CliArray; VAR ClientiFile:text); VAR Indice:IndiceTipo; BEGIN FOR Indice:=1 TO IndiceCli DO BEGIN CostruisciRecordCliente(Clienti[Indice],ClientiFile); END; Ordina(Clienti,IndiceCli) END; PROCEDURE MostraRisultati(VAR Clienti:CliArray;IndiceCli:IndiceTipo); VAR I:integer; BEGIN WITH UnCLiente DO FOR I:=1 TO IndiceCli DO writeln(Clienti[I].CognCli,' ',Clienti[I].Nazione,' ',Clienti[I].Nascita.Giorno,'/', Clienti[I].Nascita.Mese,'/',Clienti[I].Nascita.Anno); END;
10
BEGIN assign(ClientiFile,'C:\Modapr\test1.TXT'); reset(ClientiFile); LeggiRappresentante(ClientiFile, UnRappresentante, IndiceCli); readln; OrdinaClienti(IndiceCli,Clienti, ClientiFile); MostraRisultati(Clienti,IndiceCli); readln END. TP\ESEMPI|MODA
11
Esercizio n° 5 Scrivere un programma che, dato un file testo prova.txt estragga dal testo tutti i caratteri di tipo numerico sostituendoli con spazi vuoti. Memorizzare il file così corretto con il nome di prova1.txt. Fare la somma dei numeri estratti. Es. DATI Ab73cqSw1yt Ab cqSw yt A video deve comparire 73 1 Somma = 74
12
ApriFile(ProInput,ProOut); CercaNumero(ProInput,ProOut,Somma); ChiudiEStampa(ProInput,ProOut,Somma); readln ProOut ApriFile ProInput CercaNumero ProOutProInputSomma ChiudiEStampa Somma Potenza Pot CostruisciNumero PotChNumero
13
PROGRAM Esercizio5(output,ProInput,ProOut); VAR ProInput,ProOut: text; Somma:integer; FUNCTION Potenza(P:integer):integer; VAR I,Pote:integer; BEGIN Pote:=1; FOR I:=1 TO P DO Pote:=Pote*10; Potenza:=Pote END; PROCEDURE CostruisciNumero(VAR Numero,Pot:integer;Ch:char); VAR CharNum:integer; BEGIN CharNum:=ord(Ch)-ord('0'); Numero:= CharNum +Numero*potenza(Pot); END; PROCEDURE ApriFile(VAR PrIn,Prout:text); BEGIN assign(PrIn,'C:\TP\ESEMPI\TEST5.TXT'); assign(Prout,'C:\TP\ESEMPI\COPIA5.TXT'); reset(PrIn); rewrite(Prout); END;
14
PROCEDURE CercaNumero(VAR ProInp,ProOu:text; VAR Somm:integer); VAR Numero, Pot:integer; Ch: Char; BEGIN WHILE NOT eof(ProInp) DO BEGIN WHILE NOT eoln(ProInp) DO BEGIN Numero:=0; Pot:=0; read(ProInp,Ch); IF (ord(Ch) 47) THEN BEGIN WHILE (ord(Ch) 47) DO BEGIN write(ProOu,' '); CostruisciNumero(Numero,Pot,Ch); Pot:=Pot+1; read(ProInp,Ch); END; writeln(Numero); Somm:=Somm+Numero; write(ProOu,Ch); END ELSE write(ProOut,Ch); END;
15
PROCEDURE ChiudiEStampa(VAR ProInpu,ProOu:text;Som:integer); BEGIN close(ProInpu); close(ProOu); writeln('File Duplicato -- La somma vale: ',Som); END; {*************MAIN**************} BEGIN ApriFile(ProInput,ProOut); CercaNumero(ProInput,ProOut,Somma); ChiudiEStampa(ProInput,ProOut,Somma); readln END. TP\ESEMPI|MODA
16
Esercizio 3 Sia data la successione: a n =a n-3 +3*a n-2 -2*a n-1 +c Calcolare la somma dei valori della successione per n che va da 3 a un valore prefissato K sapendo che: a 0 =-1a 1 =2a 2 =-5 e che c è una costante prefissata a priori.
17
PROGRAM Esercizio3(input,output); VAR C,K,I:integer; An,An1,An2,An3:real; PROCEDURE AssegnaValori(VAR C1,K1:integer); BEGIN Write(' Dammi C '); Readln(C1); Write(' Dammi K '); Readln(K1); END; PROCEDURE CalcolaSuccessione(an11,an22,an33:real;C1,K1:integer); VAR An:real; BEGIN writeln('Valori della successione da 1 a ',K); writeln('1 = ',an11:5:0); writeln('2 = ',an22:5:0); writeln('3 = ',an33:5:0); FOR I:=3 TO K1 DO BEGIN An:=an3+3*an2*an1+C1; An3:=an2; An2:=an1; An1:=an; writeln(I:1,' = ',An:5:0); END;
18
{****************** MAIN ****************} BEGIN An3:=-1; An2:=2; An1:=-5; AssegnaValori(C,K); CalcolaSuccessione(an1,an2,an3,C,K); writeln(' FINE COMPUTAZIONE '); readln END. TP\ESEMPI|MODA
20
PROGETTO MODULO 1 - MODULO n - PROGRAMMA PRINCIPALE - Program …………………...….. end. unit xxxx ………………... end. unit yyyy ………………... end. …………………………………………. uses xxxx, yyyy;
21
DATA ABSTRACTION Qualunque tipo di dati può essere descritto sulla base dei valori che esso può prendere e delle operazioni che ad esso si possono applicare. ESEMPIO TipoValoriOperazioni integer- maxint ÷ + maxint+, -, *, DIV real 10 -38 ÷ 10 +38 +, -, *, / boolean TRUE, FALSEAND, OR, NOT
22
Un abstract data type (ADT) e un Type definito in termini del nome logico che gli si attribuisce e delle operazioni che possono essere applicate ad esso. DATA ABSTRACTION Separazione del significato logico delle operazioni in un ADT dai dettagli implementativi.
23
ESEMPIO NUMERI COMPLESSI Un numero complesso in genere è scritto come a + bi dove a e b sono dei numeri reali e i, detta parte immaginaria, ed è tale che i 2 =-1
24
Nel 1572 tale Raffaele Bombelli, colui che per primo introdusse le parentesi, propose di trattare la come una entità a parte e di applicare ad essa tutte le regole che valevano per i numeri normali. Cartesio chiamò i numeri che prevedevano la presenza della numeri immaginari mentre Gauss li chiamò complessi. Solo nel 1777 Eulero propose di sostituire con la lettera i. Notizie sui numeri complessi si trovano in il TEOREMA DEL PAPPAGALLO di Denis Guedj, ed. Longanesi, pag.326 I numeri complessi sono usati in elettrotecnica, dinamica dei fluidi, aerodinamica etc.
25
Rappresentazione grafica dei numeri complessi
26
Una ADT, una volta implementata viene memorizzata su un file e richiamata da un programma solo quando richiesta. Ognuno di questi file è definito come unit e come tale è riconosciuto dal programma principale quando viene richiamato. Progettare una ADT per i numeri complessi significa realizzare un software che permette di definire un Type Complesso e implementi tutta una serie di operazioni tipiche dei numeri complessi. Es. addizione, sottrazione, moltiplicazione, divisione, valore assoluto, ……………………………..
27
UNIT (pag. 906 testo) E un insieme di costanti, tipi, dati, variabili funzioni e procedure che può essere memorizzato su un file e compilato separatamente dal programma principale che lo chiama. Nel Turbo Pascal per compilare una unit si deve scegliere sotto la voce COMPILE loption DISK (per i programmi generali si usa invece MEMORY). Per richiamare una unit in un programma si usa la parola chiave uses nome_unit, ….;
28
interfaccia Contiene le dichiarazioni globali a tutta la unit e le definizioni di procedure e funzioni da esportare implementazione Contiene i corpi delle procedure e funzioni sopra dichiarate insieme alle dichiarazioni di costanti, tipo, variabili e procedure locali allunità. unit xxxxxxxx; interface ………. implementation ……………… end. UNIT
29
NUMERI COMPLESSI X + Yi TYPE ComplexNo=RECORD XRe, YIm: real END; ComplexNo XReYIm
30
UNIT ADTComplexNo; {documentazione} INTERFACE{sezione interfaccia} {definizioni dellADT} TYPE ComplexNo=RECORD XRe, YIm: real END; { le operazioni } PROCEDURE …………………….. FUNCTION …………………………. IMPLEMENTATION{sezione implementazioni} PROCEDURE …………………….. FUNCTION ………………………….
31
NUMERI COMPLESSI a + bi Le operazioni con i numeri complessi: Parte Reale: a Parte Immaginaria: b Modulo: Somma : (a + bi) + (c + di) = (a + c) + (b + d) i Sottrazione: (a + bi) - (c + di) = (a - c) + (b - d) i Moltiplicazione: (a + bi) * (c + di) = (ac - bd) -(ad + bc) i Divisione:
32
UNIT ADTComplexNo; {documentazione} INTERFACE {inizio della sezione INTERFACE } { definizioni dellADT } TYPE ComplexNo=RECORD Xre, Yim: real END; { le operazioni } PROCEDURE MakeComp(Xpart, Ypart:real; VAR Cnumber: ComplexNo); { costruisci il numero complesso } FUNCTION RealPart(Cnumber: ComplexNo):real; { identifica la parte reale del numero complesso } FUNCTION ImaginaryPart(Cnumber: ComplexNo):real; { identifica la parte immaginaria del numero complesso } FUNCTION Magnitude(Cnumber: ComplexNo):real; { identifica il modulo del numero complesso }
33
PROCEDURE AddComp(Term1, Term2:ComplexNo; VAR Sum: ComplexNo); { addiziona i numeri complessi Term1 e Term2 } PROCEDURE SubtrComp(Term1, Term2: ComplexNo; VAR Difference: ComplexNo); { sottrae i numeri complessi Term1 e Term2 } PROCEDURE MultComp(Factor1, Factor2: ComplexNo; VAR Product: ComplexNo); { moltiplica i numeri complessi Factor1 e Factor2 } PROCEDURE DivComp(Factor1, Factor2: ComplexNo; VAR Quotient: ComplexNo); { divide i numeri complessi Factor1 e Factor2 } { fine della sezione INTERFACE }
34
IMPLEMENTATION {inizio della sezione IMPLEMENTATION } PROCEDURE MakeComp(Xpart, Ypart:real; VAR Cnumber: ComplexNo); { costruisci il numero complesso } BEGIN Cnumber.Xre:=Xpart; Cnumber.Yim:=Ypart END; FUNCTION RealPart(Cnumber: ComplexNo):real; { identifica la parte reale del numero complesso } BEGIN RealPart:= Cnumber.Xre END; FUNCTION ImaginaryPart(Cnumber: ComplexNo):real; { identifica la parte immaginaria del numero complesso } BEGIN ImaginaryPart:= Cnumber.Yim END;
35
FUNCTION Magnitude(Cnumber: ComplexNo):real; { identifica il modulo del numero complesso } BEGIN Magnitude:= sqrt(sqr(Cnumber.Xre)+sqr(Cnumber.Yim)) END; PROCEDURE AddComp(Term1, Term2:ComplexNo; VAR Sum: ComplexNo); { addiziona i numeri complessi Term1 e Term2 (a + bi) + (c + di) = (a + c) + (b + d) i } BEGIN WITH Sum DO BEGIN Xre:=Term1.Xre+Term2.Xre; Yim:=Term1.Yim+Term2.Yim END END;
36
PROCEDURE SubtrComp(Term1, Term2:ComplexNo; VAR Difference: ComplexNo); { addiziona i numeri complessi Term1 e Term2 (a + bi) - (c + di) = (a - c) + (b - d) i } BEGIN WITH Difference DO BEGIN Xre:=Term1.Xre - Term2.Xre; Yim:=Term1.Yim - Term2.Yim END;
37
PROCEDURE MultComp(Factor1, Factor2:ComplexNo; VAR Product: ComplexNo); { addiziona i numeri complessi Term1 e Term2 (a + bi) * (c + di) = (ac - bd) -(ad + bc) i } BEGIN WITH Product DO BEGIN Xre:=Factor1.Xre * Factor2.Xre - Factor1.Yim * Factor2.Yim; Yim:=Factor1.Xre * Factor2.Yim + Factor2.Xre * Factor1.Yim END END;
38
PROCEDURE DivComp(Factor1, Factor2:ComplexNo; VAR Quotient: ComplexNo); { addiziona i numeri complessi Term1 e Term2 } VAR Divisor: real; {divisore del quoziente} BEGIN Divisor:=sqr(Factor2.Xre) + sqr(Factor2.Yim); WITH Quotient DO BEGIN Xre:=(Factor1.Xre * Factor2.Xre + Factor1.Yim * Factor2.Yim)/Divisor; Yim:= (Factor1.Yim *Factor2.Xre - Factor1.Xre * Factor2.Yim)/Divisor END END;
39
ESEMPIO Risolvere lequazione di primo grado AX+B=C con A, B, C numeri complessi. Supponiamo A 0. Soluzione: X=(C-B)/A Input: Introdurre i coefficienti nellordine: A, B, C Per ogni coefficiente introdurre prima la parte reale e poi la parte immaginaria. Ouput: Mostrare la soluzione X sotto forma di numero complesso
40
Pseudo codice Richiama la unit per i numeri complessi; Mostra le istruzioni per lintroduzione dei dati; Leggi i coefficienti; Calcola la soluzione; Mostra la soluzione. A B C X Mostra Istr.LeggiCalcolaMostra Ris. ADTComplexNo A B C X Equazione
41
PROGRAM Equazione(input,output); USES Compl; VAR A,B,C, {coefficienti} X: ComplexNo; {soluzione} PROCEDURE MostraIstruzioni; BEGIN writeln('L'' equazione e'' immaginata sotto la forma AX+B=C. ' ); writeln('I coefficienti A,B,C vanno introdotti come coppie di numeri:'); writeln('prima la parte reale e poi quella immaginaria') END;
42
PROCEDURE MC(Z:ComplexNo); {mostra il numero complesso Z} VAR Segno:STRING[3]; BEGIN Segno:=' '; IF ImaginaryPart(Z)>=0 THEN Segno:=' + '; writeln(RealPart(Z):3:1,Segno,ImaginaryPart(Z):3:1,'i'); writeln END;
43
PROCEDURE LeggiCoefficienti(VAR A,B,C:ComplexNo); VAR ARe,BRe,CRe,AIm,BIm,CIm:real; BEGIN write('Coefficiente A= '); readln(ARe,AIm); write('Coefficiente B= '); readln(BRe,BIm); write('Coefficiente C= '); readln(CRe,CIm); MakeComp(ARe,AIm,A); MakeComp(BRe,BIm,B); MakeComp(CRe,CIm,C) END;
44
PROCEDURE Soluzione(A,B,C:ComplexNo; VAR X:ComplexNo); {documentazione} VAR CmenoB:ComplexNo; BEGIN SubtrComp(C,B,CmenoB); DivComp(CmenoB,A,X) END; PROCEDURE MostraRisultato(X:ComplexNo); BEGIN writeln('La radice dell''equazione assegnata e'': '); MC(X) END;
45
{ BODY } BEGIN MostraIstruzioni; LeggiCoefficienti(A,B,C); Soluzione(A,B,C,X); MostraRisultato(X) END.
46
L' equazione e' immaginata sotto la forma AX+B=C. I coefficienti A,B,C vanno introdotti come coppie di numeri: prima la parte reale e poi quella immaginaria Coefficiente A= 5 66 Coefficiente B= 77 55 Coefficiente C= 4 2 La radice dell'equazione assegnata e': -0.9 + 1.0i OUTPUT
47
ESERCIZIO 1-B Progettare e realizzare una Unit che permetta il calcolo delle aree e dei perimetri delle seguenti figure geometriche: Triangolo rettangolo – assegnata la base e laltezza Rettangolo – assegnata la base e laltezza Utilizzando la Unit di cui sopra trovare larea dellappartamento la cui planimetria è data in figura assegnando alle dimensioni a,b,c,d,e,f valori a piacere (da tastiera) e per ogni vano calcolare la superficie complessiva dei muri sapendo che laltezza di ogni vano vale k. e a b c d f
48
REGOLE GENERALI PER LA PROGETTAZIONE DI UNIT ADT Completezza: non necessita di operazioni addizionali per essere usata Ogni operazione deve appartenere ad una delle seguenti categorie: Constructor - cambia o inizializza i valori di una variabile astratta Primitive constructor - assegna un valore ad una variabile astratta senza fare uso di altre variabili astratte dello stesso tipo. Ha una sola variabile di output e quelle di input servono per costruire loutput. Es. MakeComp(Xpart, Ypart:real; VAR Cnumber: ComplexNo); { costruisci il numero complesso } Ogni ADT richiede almeno un Primitive constructor così che il client può assegnare un valore iniziale alla variabile astratta.
49
Non-primitive constructor -. Ha almeno una variabile di input il cui tipo è uguale a quello delloutput. Es. AddComp(Term1, Term2:ComplexNo; VAR Sum: ComplexNo); { addiziona i numeri complessi Term1 e Term2 }
50
SELECTOR - fornisce informazioni su una variabile di input ADT ad un parametro di uscita. Spesso è una funzione (il parametro di uscita in tal caso è la funzione stessa). Primitive selector - ritorna il valore di uno dei componenti della variabile astratta. Es. RealPart(Cnumber: ComplexNo):real; { identifica la parte reale del numero complesso } Ogni unit necessita di un Primitive selector altrimenti il client non può mostrare i valori della variabile. Non-primitive selector - ritorna il valore che non è relativo ad uno dei componenti della variabile astratta ma ciò nonostante è utile al client. Es. Magnitude(Cnumber: ComplexNo):real; { identifica il modulo del numero complesso }
51
PREDICATE - è una funzione booleana che ritorna informazioni sul valore o lo stato di una variabile astratta.
52
Un ADT è completa se il client : fa riferimento solo al type dellADT (es. ComplexNo) non deve mai cambiare la logica delle operazioni dellunit non deve mai aver bisogno di altre operazioni Ogni unit ADT deve avere : un primitive constructor i valori devono poter essere letti e scritti tutte le operazioni prevedibili per il tipo di ADT
54
Head LE CODE (QUEUE) Tail Head
55
LE CODE (QUEUE) Le operazioni fondamentali che si fanno sulle code sono: riempimento e svuotamento. Questo implica che durante lo svolgimento del programma il numero di oggetti in coda può cambiare. Dynamic data type: il numero di componenti nel Data Type cambia nel corso del programma. Dobbiamo descrivere una queue in funzione della sua head (testa), della sua tail (coda), degli oggetti in coda e del loro numero in ogni istante della computazione.
56
OPERAZIONI SULLE CODE In una coda lelemento inserito per primo viene anche estratto per primo (FIFO). In una coda occorerrà allora distinguere tra un inizio o TESTA della coda (punto di estrazione e/o cancellazione di un elemento) ed una fine o CODA della coda (punto di inserimento di un nuovo elemento). Aggiungere ed eliminare oggetti. Se Items[ ] è un array in cui si collocano gli oggetti. Head lindice dellarray corrispondente alla Testa, Tail lindice corrispondente alla coda e Item loggetto da aggiungere potremmo usare i seguenti algoritmi:
57
OPERAZIONI SULLE CODE AGGIUNGERE Tail Tail+1 Items[Tail] Item InUse InUse + 1 ELIMINARE Head Head+1 InUse InUse - 1 SOLUZIONE IMPROPONIBILE !!!!!!!!!!!! Ogni volta che esce un oggetto bisogna spostare in avanti di un posto tutti quelli in coda altrimenti lo spazio disponibile si esaurisce rapidamente pur essendoci posti vuoti.
58
Escono due oggetti e ne entrano tre Escono due oggetti e ne entrano due TestaCoda 1 2 3 4 5 6 7 8 9 N°=6 TestaCoda 1 2 3 4 5 6 7 8 9 N°=6 Testa Coda 1 2 3 4 5 6 7 8 9 N°=7
59
Gli indici che caratterizzano Head e Tail devono variare tra 1 e 9. Se si supera 9 e nelle posizioni da 1 a indice di Head cè ancora posto allora gli indici di Head e Tail devono adeguatamente modificarsi per sfruttare sempre tutti gli spazi disponibili. entraesceheadtailin use 00166 01265 01364 10375 10386 01485 01584 10595 10516 10527
60
Possiamo descrivere una queue in funzione della sua head (testa), della sua tail (coda), degli oggetti in coda e del loro numero in ogni istante della computazione utilizzando lespressione Tail:=Tail MOD MaxQueue + 1 Head:=Head MOD MaxQueue + 1 è infatti facile mostrare che con queste espressioni Tail e Head assumeranno giusto i valori indicati nella tabella precedente nel caso dellesempio mostrato.
61
LE CODE (QUEUE) Le queue si riempiono aggiungendo oggetti in coda e si svuotano a partire dalla testa. Supponiamo di voler gestire con un meccanismo a coda 100 oggetti di tipo stringa.
62
UNIT Code; {documentazione} INTERFACE{sezione interfaccia} {definizioni dellADT} CONST MaxQueue=100; NullItem=; TYPE ItemType=STRING[20] massima lunghezza delle stringhe QueueType=RECORD Head, primo oggetto nella coda Tail : 1..MaxQueue; ultimo oggetto nella coda InUse :0..MaxQueue; numero di oggetti in coda Items: ARRAY[1..MaxQueue] OF ItemType contiene gli oggetti in coda END; TailInUse Items QueueType Head
63
{ le operazioni } PROCEDURE MakeQueue(VAR Queue:QueueType); { inizializza la coda vuota } PROCEDURE AddQueue(Item:ItemType; VAR Queue:QueueType); { se la coda non è piena aggiungi oggetti altrimenti segnala errore } PROCEDURE DeleteQueue(VAR Queue:QueueType); {se la coda non è vuota elimina il primo oggetto altrimenti segnala errore} PROCEDURE FirstOnQueue(VAR Queue:QueueType; VAR Item:ItemType); {assegna a Item il valore del primo oggetto in coda, in mancanza assegna valore nullo}
64
FUNCTION QCount(VAR Queue:QueueType; ):integer; { identifica quanti oggetti sono in coda } FUNCTION QEmpty(VAR Queue:QueueType; ):boolean; { vera se non ci sono oggetti in coda } FUNCTION QFull(VAR Queue:QueueType; ):boolean; { vera se la coda è piena } { fine della sezione INTERFACE }
65
IMPLEMENTATION {inizio della sezione IMPLEMENTATION } PROCEDURE MakeQueue(VAR Queue:QueueType); { inizializza la coda vuota } BEGIN WITH Queue DO BEGIN Head:=1; Tail:=MaxQueue; InUse:=0 END END; TailInUse Items QueueType Head
66
PROCEDURE AddQueue(Item:ItemType; VAR Queue:QueueType); { se la coda non è piena aggiungi oggetti altrimenti segnala errore } BEGIN WITH Queue DO IF InUse<>MaxQueue THEN BEGIN Tail:=Tail MOD MaxQueue+1 Items[Tail]:=Item; InUse:=InUse+1 END ELSE writeln(Errore: la coda è piena) END; TailInUse Items QueueType Head
67
PROCEDURE DeleteQueue(VAR Queue:QueueType); {se la coda non è vuota elimina il primo oggetto altrimenti segnala errore} BEGIN WITH Queue DO IF InUse<>0 THEN BEGIN Head:=Head MOD MaxQueue+1 InUse:=InUse-1 END ELSE writeln(Errore: la coda è vuota) END; TailInUse Items QueueType Head
68
PROCEDURE FirstOnQueue(VAR Queue:QueueType; VAR Item:ItemType); {assegna a Item il valore del primo oggetto in coda, in mancanza assegna valore nullo} BEGIN WITH Queue DO IF InUse<>0 THEN Item:=Items[Head] ELSE Item:=NullItem END; TailInUse Items QueueType Head
69
FUNCTION QCount(VAR Queue:QueueType; ):integer; { identifica quanti oggetti sono in coda } BEGIN QCount:=Queue.InUse END; FUNCTION QEmpty(VAR Queue:QueueType; ):boolean; { vera se non ci sono oggetti in coda } BEGIN QEmpty:=(Queue.InUse=0) END; TailInUse Items QueueType Head
70
FUNCTION QFull(VAR Queue:QueueType; ):boolean; { vera se la coda è piena } BEGIN QFull:=(Queue.InUse=MaxQueue) END; { fine della sezione IMPLEMENTATION } TailInUse Items QueueType Head
71
Alcune considerazioni sulla complessità. Si noti che abbiamo sempre usato la chiamata VAR per la variabile Queue perché in questa maniera in un solo passo di computazione O(1) abbiamo a disposizione larray Queue mentre in caso contrario ogni volta avremmo usato la copia dellarray che ci costa O(N) passi.
72
Constructor - cambia o inizializza i valori di una variabile astratta Primitive constructor - assegna un valore ad una variabile astratta senza fare uso di altre variabile astratte dello stesso tipo. Ha una sola variabile di output e quelle di input servono per costruire loutput. PROCEDURE MakeQueue(VAR Queue:QueueType); { inizializza la coda vuota } Ogni ADT richiede almeno un Primitive constructor così che il client può assegnare un valore iniziale alla variabile astratta. Non-primitive constructor -. Ha almeno una variabile di input e il cui tipo è uguale a quello delloutput. Es. PROCEDURE AddQueue(Item:ItemType; VAR Queue:QueueType); { se la coda non è piena aggiungi oggetti altrimenti segnala errore }
73
SELECTOR - fornisce informazioni su una variabile di input ADT ad un parametro di uscita. Spesso è una funzione (il parametro di uscita in tal caso è la funzione stessa). Primitive selector - ritorna il valore di uno dei componenti della variabile astratta. Es. PROCEDURE FirstOnQueue(VAR Queue:QueueType; VAR Item:ItemType); {assegna a Item il valore del primo oggetto in coda, in mancanza assegna valore nullo} Ogni unit necessita di una Primitive selector altrimenti il client non può mostrare i valori della variabile.
74
Non-primitive selector - ritorna il valore che non è relativo ad uno dei componenti della variabile astratta ma ciò nonostante è utile al client. Es. FUNCTION QCount(VAR Queue:QueueType; ):integer; { identifica quanti oggetti sono in coda }
75
FUNCTION QEmpty(VAR Queue:QueueType; ):boolean; { vera se non ci sono oggetti in coda } BEGIN QEmpty:=(Queue.InUse=0) END; PREDICATE - è una funzione booleana che ritorna informazioni sul valore o lo stato di una variabile astratta.
76
Per un corretto funzionamento delle Unit è necessario che ogni operatore esegua una e una sola operazione e che solo i parametri necessari e sufficienti siano passati alla procedura. Se una operazione soddisfa questi criteri è detta pura. PROCEDURE DeleteQueue(VAR Queue:QueueType); BEGIN WITH Queue DO IF InUse<>0 THEN BEGIN Head:=Head MOD MaxQueue+1 InUse:=InUse-1 END ELSE writeln(Errore: la coda è vuota) END; PROCEDURE DeleteQueue(VAR Queue:QueueType;VAR Item:ItemType); BEGIN WITH Queue DO IF InUse<>0 THEN BEGIN Head:=Head MOD MaxQueue+1 InUse:=InUse-1 END ELSE writeln(Errore: la coda è vuota) END; Questo parametro è inutile e fuorviante CONSIGLI PER UNA CORRETTA PROGRAMMAZIONE
77
Ogni UNIT deve avere solo operazioni pure. Ogni operazione deve essere assolutamente necessaria altrimenti non va inserita nella UNIT. Ogni operazione deve fare una sola cosa altrimenti si corrono rischi di errori. Ogni operazione deve fare una sola cosa altrimenti si corrono rischi di errori che possono, in maniera nascosta riversarsi su tutto il programma. La logica utilizzata allinterno della UNIT deve essere del tutto trasparente per il client.
78
GESTIONE ERRORI Ogni operazione deve essere dotata di sistemi di controllo per evitare errori. PROCEDURE DeleteQueue(VAR Queue:QueueType); {se la coda non è vuota elimina il primo oggetto altrimenti segnala errore} BEGIN WITH Queue DO IF InUse<>0 THEN BEGIN Head:=Head MOD MaxQueue+1 InUse:=InUse-1 END ELSE writeln(Errore: la coda è vuota) END;
79
GESTIONE ERRORI Ogni operazione di una unit deve possedere messaggi di errore che arrestino la computazione e consentano allutente di fare le opportune correzioni senza mandare in crash il sistema. Una adeguata illustrazione delle segnalazioni di errore, delle cause che li possono produrre e dei provvedimenti da prendere va fatta nellambito del manuale di accompagnamento del software.
80
NORME PER FARE GLI ESERCIZI Nome file: cognome+iniziale nome In testa ad ogni programma devono essere scritti i dati dello studente. Es. nome file -> BianchiG {programma sviluppato da Bianchi Giulio mat. 050/888} PROGRAM …….
81
ESERCIZIO 2 B Vogliamo simulare lattività di un bistrot parigino che vende solo caffè a coppie di giovani. Il numero di tavolini è limitato e il numero di caffè da vendere è stabilito allinizio. Useremo una coda fatta di stringhe, ognuna delle quali è il nome dei clienti ai tavoli che attendono il caffè. Il barman si comporta così. Inizialmente stabilisce quanti caffè deve vendere (un numero pari). Successivamente si predispone ad accettare uno dei seguenti comandi e quindi li esegue. - A (fai accomodare): se in coda ci sono meno di tre clienti il barman accetta la nuova coppia e la fa accomodare altrimenti rifiuta il posto. - S (porta il caffè) se almeno un tavolino è occupato porta il caffè al primo arrivato, se non cè nessuno si arrabbia. Se sono terminati i caffè si mandano via quelli che sono rimasti al tavolo. Si presume che preso il caffè il tavolo si libera subito. - R (riassunto): comunica il numero di caffè venduti, il numero di caffè rimasti e la lunghezza della coda.
82
ALGORITMO del Bistrot Inizializza(VAR Queue: QueueType; VAR TotaleDaVendere:integer); TotaleVenduto 0; ChiedereNumeroCaffè DaVendere WHILE DaVendere>0 Azione IF Azione IN [a,A,V,v,r,R] THEN CASE Azione OF a,A: IncrementaCoda(Queue); s,S: Vendita(Queue,TotaleVenduto,TotaleDaVendere) r,R: Riassunto(TotaleVenduto,TotaleDaVendere,ContaCoda) MostraMessaggioPerFineCaffè.
83
PROGRAM Bistrot(input,output); {Simula una coda per servire il caffè a coppie di giovani } { La coda finisce quando tutti i tavolini sono occupati} USES Coda; CONST MaxSize=3; {dimensione massima della coda} Urlo=xxxxxxxxxxxxxx; Urlo2=ssssssssssssss'; VAR Queue:QueueType; TotaleVenduto,{totale caffè venduti } TotaleDaVendere: integer;{caffè da vendere } Azione: char;{lettera del menu per fare le scelte }
84
PROCEDURE Inizializza(VAR Queue:QueueType; VAR TotaleDaVendere:integer); {fa partire la coda e legge un numero pari di caffè da vendere } BEGIN MakeQueue(Queue); write('Quanti caffè dobbiamo preparare oggi? '); readln(TotaleDaVendere); TotaleDaVendere:=abs(TotaleDaVendere);{garanzia contro I numeri negativi } IF TotaleDaVendere MOD 2 <>0 THEN TotaleDaVendere:=TotaleDaVendere-1 END; PROCEDURE IncrementaCoda(VAR Queue:QueueType); { } VAR Name:ItemType;{Nome da aggiungere alla coda } BEGIN IF Qcount(Queue)<MaxSize THEN BEGIN write('Nome: '); readln(Name); writeln(Name, ' accomodatevi al tavolo, prego.'.');writeln; AddQueue(Name,Queue) END ELSE writeln('Mi dispiace i tavoli sono tutti occupati. ); writeln; END;
85
PROCEDURE Vendita(VAR Queue:QueueType; VAR TotaleVenduto, TotaleDaVendere:integer); { } VAR Name:ItemType;{nome del cliente } BEGIN IF NOT Qempty(Queue) THEN BEGIN FirstOnQueue(Queue,Name); TotaleVenduto:=TotaleVenduto+2; TotaleDaVendere:=TotaleDaVendere-2; write(Name); writeln(' Prego accomodatevi'); DeleteQueue(Queue) END ELSE writeln(Urlo2) END;
86
PROCEDURE Riassunto(TotaleVenduto, TotaleDaVendere, OnQueue:integer); { mostra la situazione dei biglietti e della coda} BEGIN write(TotaleVenduto:1,' biglietti venduti, e '); writeln(' la lunghezza della coda e'' ',OnQueue,'.'); writeln(' Sono rimasti ancora ',TotaleDaVendere:1,' biglietti da vendere.') END; PROCEDURE MostraRifiuto(Queue:QueueType); { } VAR Name:ItemType; {nome della persona a cui chiede scusa } BEGIN WHILE NOT Qempty(Queue) DO BEGIN FirstOnQueue(Queue,Name); writeln('Scusate don ',Name,', i bigliette sono finiti.'); DeleteQueue(Queue) END END;
87
{ BODY } BEGIN Inizializza(Queue,TotaleDaVendere); TotaleVenduto:=0; writeln(Urlo); WHILE TotaleDaVendere>0 DO BEGIN write('Azione: '); readln(Azione); IF Azione IN ['A','a', 'S','s','R','r'] THEN CASE Azione OF 'A','a': IncrementaCoda(Queue); 'S','s': Vendita(Queue,TotaleVenduto,TotaleDaVendere); 'R','r': Riassunto(TotaleVenduto,TotaleDaVendere,QCount(Queue)) END END; MostraRifiuto(Queue); readln END.
89
Top STACK
90
Le operazioni fondamentali che si fanno sugli stack sono: riempimento e svuotamento. Questo implica che durante lo svolgimento del programma il numero di oggetti nello stack può cambiare. Anche lo stack come la queue è un Dynamic data type (il numero di componenti nel Data Type cambia nel corso del programma). Per descrivere uno stack è sufficiente sapere quali sono gli oggetti (Items) nello stack e il loro numero (Top). STACK
91
OPERAZIONI SUGLI STACK In uno stack lelemento inserito per ultimo viene estratto per primo (LIFO - Last In First Out). In uno stack occorrerrà solo conoscere il numero di oggetti (Top). Aggiungere ed eliminare oggetti. Items[ ] è un array in cui si collocano gli oggetti, Top il numero di oggetti, loperazione di aggiungere oggetti si chiama push e quella di eliminare oggetti pop. Quando Top=0 allora lo stack è vuoto.
92
OPERAZIONI SUGLI STACK AGGIUNGERE Top Top + 1 Items[Top] Item ELIMINARE Top Top - 1
93
STACK Supponiamo di voler gestire con un meccanismo a STACK 100 caratteri.
94
UNIT Stack; {documentazione} INTERFACE{sezione interfaccia} {definizioni dellADT} CONST MaxStack=100; massimo numero di caratteri che si possono trattare TYPE ItemType=char; StackType=RECORD Top : 0..MaxStack; numero di oggetti presenti Items: ARRAY[1..MaxStack] OF ItemType contiene gli oggetti END; Items StackType Top
95
{ le operazioni } PROCEDURE MakeStack(VAR Stack:StackType); { inizializza lo stack vuoto } PROCEDURE Push(Item:ItemType; VAR Stack:StackType); { se lo stack non è pieno aggiungi oggetti altrimenti segnala errore } PROCEDURE Pop(VAR Stack:StackType); {se lo stack non è vuoto elimina il primo oggetto altrimenti segnala errore} FUNCTION StackTop(VAR Stack:StackType): ItemType; {se lo stack non è vuoto la funzione assume il valore delloggetto al top dello stack, in mancanza assume valore nullo chr(0)}
96
FUNCTION StackEmpty(VAR Stack:StackType; ):boolean; { vera se non ci sono oggetti nello stack } FUNCTION StackFull(VAR Stack:StackType; ):boolean; { vera se lo stack è pieno } { fine della sezione INTERFACE }
97
IMPLEMENTATION {inizio della sezione IMPLEMENTATION } PROCEDURE MakeStack(VAR Stack:StackType); { inizializza lo stack vuoto } BEGIN Stack.Top:=0; END; Items StackType Top
98
FUNCTION StackEmpty(VAR Stack:StackType; ):boolean; { vera se non ci sono oggetti nello stack } BEGIN StackEmpty:=(Stack.Top=0) END; Items StackType Top FUNCTION StackFull(VAR Stack:StackType; ):boolean; { vera se lo stack è pieno } BEGIN StackFull:=(Stack.Top=MaxStack) END;
99
FUNCTION StackTop(VAR Stack:StackType): ItemType); {se lo stack non è vuoto la funzione assume il valore delloggetto al top dello stack, in mancanza assume valore nullo chr(0)} BEGIN WITH Stack DO IF Top=0 THEN StackTop:=chr(0) ELSE StackTop :=Items[Top] END; Items StackType Top
100
PROCEDURE Push(Item:ItemType; VAR Stack:StackType); { se lo stack non è pieno aggiungi oggetti altrimenti segnala errore } WITH Stack DO IF Top<>MaxStack THEN BEGIN Top:=Top+1; Items[Top]:=Item; END ELSE writeln(Errore: lo stack è pieno) END; Items StackType Top
101
PROCEDURE Pop(VAR Stack:StackType); {se lo stack non è vuoto elimina il primo oggetto altrimenti segnala errore} BEGIN WITH Stack DO IF Top<>0 THEN Top:=Top-1 ELSE writeln(Errore: lo stack è vuoto) END; { fine della sezione IMPLEMENTATION } Items StackType Top
102
Constructor Primitive constructor - assegna un valore ad una variabile astratta senza fare uso di altre variabile astratte dello stesso tipo. Ha una sola variabile di output e quelle di input servono per costruire loutput. PROCEDURE MakeStack(VAR Stack:StackType); { inizializza lo stack vuoto } Ogni ADT richiede almeno un Primitive constructor così che il client può assegnare un valore iniziale alla variabile astratta. Non-primitive constructor -. Ha almeno una variabile di input e il cui tipo è uguale a quello delloutput. Es. PROCEDURE Push(Item:ItemType; VAR Stack:StackType); { se lo stack non è pieno aggiungi oggetti altrimenti segnala errore }
103
SELECTOR - fornisce informazioni su una variabile di input ADT ad un parametro di uscita. Spesso è una funzione (il parametro di uscita in tal caso è la funzione stessa). Primitive selector - ritorna il valore di uno dei componenti della variabile astratta. Es. FUNCTION StackTop(VAR Stack:StackType): ItemType; {se lo stack non è vuoto la funzione assume il valore delloggetto al top dello stack, in mancanza assume valore nullo chr(0)} Ogni unit necessita di una Primitive selector altrimenti il client non può mostrare i valori della variabile.
104
Non-primitive selector - ritorna il valore che non è relativo ad uno dei componenti della variabile astratta ma ciò nonostante è utile al client. NESSUNA
105
PREDICATE - è una funzione booleana che ritorna informazioni sul valore o lo stato di una variabile astratta. FUNCTION StackEmpty(VAR Stack:StackType; ):boolean; { vera se non ci sono oggetti nello stack } FUNCTION StackFull(VAR Stack:StackType; ):boolean; { vera se lo stack è pieno }
106
Alcuni commenti Si noti che sia nella unit della QUEUE che in quella degli STACK abbiamo adoperato una variabile ItemType per indicare il tipo di oggetti che volevamo trattare con le nostre strutture. Questo sistema ci permette di modificare in maniera molto semplice le due Unit nel momento in cui volessi trattare integer invece che stringhe o real invece che caratteri. Non è però sufficiente la modifica del solo ItemType in alcune funzioni o procedure, ad esempio quelle di controllo dellerrore. La scelta di usare nelle FUNCTION la call per VAR invece che per valore pur se questa scelta impegna più memoria però in compenso la chiamata avviene in un tempo di complessità pari a O(1) invece che O(N).
107
ESEMPIO N.1 Assegnato un file contenente stringhe di caratteri riscrivere, rigo per rigo, il file con i caratteri in ordine inverso. Esempio: Oggi è una bella giornata che diventa atanroig alleb anu è iggo Soluzione Leggere il file carattere per carattere e introdurre i singoli caratteri, nellordine in cui appaiono in uno stack. Il contenuto dello stack a partire dal Top andando verso sinistra sarà la risposta al nostro problema.
108
Pseudo Codice MakeStack(ChStack){inizializza uno stack vuoto} WHILE NOT eoln DO read(Ch) push Ch in ChStack readln WHILE ChStack non è vuoto DO mostra il valore di Ch nel Top pop il valore di Ch dal Top dello Stack writeln
109
PROGRAM InvertiRigo(input,output); {documentazione} USES Stack; VAR ChStack:StackType Ch:char {carattere da inserire o eliminare dallo stack} BEGIN MakeStack(ChStack); WHILE NOT eoln DO BEGIN read(Ch); Push(Ch,ChStack); END; readln; WHILE NOT StackEmpty(ChStack) DO BEGIN Ch:=StackTop(ChStack); Pop(ChStack); write(Ch) END; writeln; END.
110
ESEMPIO N. 2 Assegnata una espressione contenente parentesi controllare che lapertura e chiusura di queste sia bilanciata. Supponiamo che le parentesi siano del tipo: ApertaChiusa { } [ ] ( ) Esempio {a+[ b*c - (d-a) ]+d} Re:=sqrt(sqr(A[3,5]+33)
111
Soluzione Si legge la stringa contenente le parentesi. Quando appare una parentesi aperta si inserisce in uno stack. Non appena appare la prima parentesi chiusa si confronta questa con la parentesi contenuta nel Top dello Stack. Se le parentesi sono uguali si prosegue altrimenti si dichiara che le parentesi non sono ben bilanciate. Pseudo Codice MakeStack(ChStack) Bilanciato TRUE FOR Posizione 1 TO lenght(Linea) DO Ch Linea[Posizione] IF Ch è una parentesi aperta THEN Push(Ch,ChStack) ELSE IF Ch è una parentesi chiusa THEN IF NOT Matched(StackTop(ChStack),Ch) THEN Bilanciato FALSE Pop(ChStack) Linea Bilanciata Bilanciato AND StackEmpty(ChStack)
112
FUNCTION Matched(LeftCh, RightCh:char):boolean; {ritorna vero se la parentesi aperta e quella chiusa sono dello stesso tipo} BEGIN Matched:= (LeftCh={) AND (RightCh=}) OR (LeftCh=[) AND (RightCh=]) OR (LeftCh=() AND (RightCh=)) END;
113
FUNCTION LineaBilanciata (Linea:LineString):boolean; {ritorna vero se la parentesi aperte e chiuse sono bilanciate} VAR Posizione:1..80; Ch:char; Bilanciato : boolean; ChStack: StackType; BEGIN MakeStack(ChStack); Bilanciato :=TRUE; FOR Posizione:=1 TO lenght(Linea) DO BEGIN Ch:=Linea[Posizione]; IF Ch IN [{,[,(] THEN Push(Ch,ChStack) ELSE IF Ch IN [}, ],,)] THEN BEGIN IF NOT Matched(StackTop(ChStack),Ch) THEN Bilanciato :=FALSE; Pop(ChStack) END; BalancedLine:= Bilanciato AND StackEmpty(ChStack) END;
114
ESEMPIO PROCEDURE ANNIDATE Proc A Proc B Proc C ……………. Proc B Proc A
115
Esercizio Dato un numero verificare se esso è palindromo. Si definisce palindromo un numero (o stringa) che può essere letto indifferentemente da sinistra verso destra e da destra verso sinistra. Es.12324423217659567 Un numero (o stringa) palindromo si dice pari se il numero delle cifre (caratteri) che lo compongono è pari, dispari altrimenti. Esercizio Addizionare due numeri interi di grandezza superiore a 2 15.
116
Un suggerimento Quando si scrivono delle ADT invece di inserire scritte che ne controllino la correttezza di funzionamento è opportuno inserire in esse funzioni o procedure aventi lo stesso scopo così da poterle utilizzare anche dopo che la Unit è stata compilata per ulteriori controlli.
117
Primo progetto intercorso Simulare lattività di un distributore automatico di generi alimentari in cui sono in vendita prodotti con data di scadenza. Siano tre le linee di prodotti: A, B, C. I prodotti A possono rimanere nel distributore 3 giorni I prodotti B possono rimanere nel distributore 5 giorni I prodotti C possono rimanere nel distributore 4 giorni I prodotti vengono dati al pubblico in funzione della data di scadenza, prima quelli più antichi. Simulare il caricamento di ogni prodotto con un massimo numero di pezzi (maxA, maxB, maxC). Simulare la vendita dei tre prodotti con segnalazione di fine prodotto. Simulare la raccolta a fine settimana dei prodotti scaduti tenendo presente che essi vanno riconsegnati a diversi distributori. Poiché i distributori sono in luoghi diversi verranno caricati sui camion prima i prodotti di tipo B, poi quelli C e infine quelli A. Simulare infine la consegna dei prodotti ai distributori.
Presentazioni simili
© 2024 SlidePlayer.it Inc.
All rights reserved.