Tema2

Responsabili:

Obiective

  • Aprofundarea cunoștințelor în utilizarea limbajului C++
  • Implementarea și utilizarea structurii de date hashtable(generică)
  • Modelarea unei hărți rutiere sub forma unui graf orientat pentru o rezolvare eficientă a problemei
  • Elaborarea unei rezolvări complexe la o cerință inspirată din realitate

Introducere

O hartă rutieră a unui oraș, definită prin intersecții și străzi între aceste intersecții, poate fi reprezentată sub forma unui graf orientat în care nodurile reprezintă intersecțiile, iar muchiile reprezintă străzile (vom considera străzile că fiind unidirecționale). O astfel de reprezentare a unei hărți rutiere este foarte eficientă pentru a determina diferite proprietăți ale acesteia (conectivitatea între diferite intersecții, care sunt cele mai frecventate rute, cel mai scurt drum între două puncte de interes etc.).

Enunț

Fiind date intersecțiile în ordinea lor lexicografică și străzile dintre ele, să se afișeze următoarele informații:

  • existența unui traseu între două intersecții date
  • distanța dintre două intersecții (dacă există acest drum)
  • după apariția unor modificări ale străzilor (inversare sens, blocare, adăugare, transformare în stradă bidirecțională), se cer următoarele informații despre perechile de noduri date:
    • existența unui drum
    • distanța
    • distanța cu oprire intermediară
  • se vor simula mai multe curse de tip Uber; veți primi informații despre poziția șoferilor pe harta; pentru fiecare cursă vom actualiza informații în legătură cu șoferul (rating, locație, nr de curse, distanță totală); pe parcursul curselor se vor cere topuri legate de aceste informații
  • primind numele unui șofer și cantitatea de combustibil disponibilă, și o listă de intersecții, să se determine lista sortată după cantitatea de combustibil cu care se ajunge în fiecare

Noțiunile definite mai sus vor fi explicate în detaliu în secțiunea următoare.

Clarificări

Generale

  • considerăm lungimea oricărei străzi ca fiind 1 unitate;
  • considerăm lumgimea drumului minim între două străzi că fiind numărul minim de muchii care trebuie parcurse pentru a ajunge de la o intersecție la alta;

Task 1

La acest task va trebui să verificați dacă pentru o pereche de intersecții (start, end) există un drum valid de la start la end. În cazul în care există va trebui să scrieți în fișier y, iar în caz contrar n.

Task 2

Asemănător primului task, va trebui să afișați distanta dintre două intersecții primite la input. În cazul în care există drum, veți afișa un număr întreg reprezentând lungimea drumului, altfel -1.

Task 3

Harta poate suferi modificări pe parcurs. Aceste modificări pot fi de tipul adăugare drum între două intersecții, schimbarea sensului unui drum, transformarea unui drum unidirecțional în unul bidirecțional sau blocarea totală a unui drum. Având informații despre toate aceste modificări, și interogări pe parcursul modificărilor, va trebui să afișați dacă există un drum între două intersecții, distanța între două intersecții și distanța dintre două intersecții trecând obligatoriu printr-o a treia intersecție (oprire intermediară).

Hint: În anumite situații, este util să precalculați anumite informații din graf, înainte de a aplica anumite operații.

Task 4

Dorim să simulăm comportamentul aplicației unui serviciu de curse tip Uber. Harta folosită este cea obținută în urmă modificărilor de la task 3. Veți primi un set de query-uri de tipul (start, destinație, rating) simbolizând poziția de start a unui client, destinația și rating-ul pe care îl va oferi șoferului în urma călătoriei. Va trebui să determinați șoferul care va îndeplini călătoria. Pentru această vom alege cel mai apropiat șofer de poziția de start. Dacă există mai mulți șoferi aflați la aceeași distanță se va alege șoferul cu ratingul mediu mai bun. Dacă șoferii au același rating mediu, se va alege șoferul cu numele mai mic din punct de vedere lexicografic. În cazul în care niciun șofer nu poate să ajungă la poziția de start, se va afișa mesajul “Nu există șoferi disponibili!”. Dacă destinația nu este accesibilă din punctul de start, inițial se va încerca să se ajungă la oricare din nodurile vecine destinației(pentru care există drum de la destinație la ele); dacă nu este posibil acest lucru, se va afișa mesajul “Destinație inaccesibilă!”. După ce un șofer duce o cursă la sfârșit, noua lui poziție va fi actualizată cu destinația cursei.

Pentru a adaugă șoferi pe hartă, printre aceste query-uri veți primi și input de adăugare a șoferilor, actualizare a poziției și/sau statusului. Un șofer poate avea două statusuri: online și offline. În momentul în care un șofer își schimbă statusul în offline acesta nu mai poate prelua curse. Dacă își schimbă statusul din nou în online, va putea prelua curse. Atenție, în momentul în care un șofer devine din nou online va putea prelua din nou clienți și își va păstra toate statisticile de dinainte. De asemenea, în momentul în care redevine online acesta se poate afla în altă intersecție decât în cea în care se afla anterior.

De asemenea, între călătorii veți avea query-uri care vă vor cere topuri/informații despre statisticile ce trebuie colectate: rating mediu al fiecărui șofer, distanța parcursă în total, numărul de curse îndeplinite și locația actuală a acestuia. Pentru a răspunde la aceste query-uri veți ține cont și de șoferii care sunt online, dar și de cei offline. Inițial toți șoferii vor avea rating = 0.00, distanță = 0 și curse = 0.

Amănunte despre aceste query-uri veți găsi în secțiunea de detaliere a inputului.

Task 5

La finalul zilei, după ce toate cursele au fost duse la îndeplinire și șoferii se află în noile locații, vrem să vedem ce destinații sunt disponibile având la dispoziție o anumită cantitate de combustibil. Va trebui ca pentru un șofer, o cantitate de combustibil și o listă de puncte de interes să afișați intersecțiile în ordine crescătoare a combustibilului rămas la finalul călătoriei către fiecare punct de interes. Considerăm consumul ca fiind 1 unitate de volum / 1 unitate de distanță. Dacă o intersecție nu e accesibilă sau cantitatea de combustibil e insuficientă, nu o vom afișa la output. Pentru cantități egale de combustibil rămas, intersecțiile se vor afișa în ordine lexicografică.

Exemplu de funcționare

Date de intrare

  1. Numărul N de intersecții, numărul M de străzi;
  2. Lista numelor intersecțiilor: <nume_0 nume_1 nume_2 … nume_N-1>, unde nume_i < nume_i+1 din punct de vedere lexicografic;
  3. M linii de forma <nume_intersecție_a nume_intersecție_b> cu semnificația că există o stradă unidirecțională de la nume_intersecție_a la nume_intersecție_b
  4. Task 1:
    1. Un număr Q1, ce reprezintă numărul de query-uri pentru task-ul 1;
    2. Q1 linii de forma <nume_intersecție_1 nume_intersecție_2>, ce reprezintă intersecțiile pentru care trebuie să răspundeți dacă există un drum de la nume_intersecție_1 la nume_intersecție_2;
  5. Task 2:
    1. Un număr Q2, ce reprezintă numărul de query-uri pentru task-ul 2;
    2. Q2 linii de forma <nume_intersecție_1 nume_intersecție_2>, ce reprezintă intersecțiile pentru care trebuie să afișați distanta drumului de la nume_intersecție_1 la nume_intersecție_2;
  6. Task 3:
    1. Un număr Q3, ce reprezintă numărul de query-uri și schimbări de drum specifice taskului 3;
    2. Q3 linii ce pot avea forma:
      1. <c intersecție_a intersecție_b 0> - se construiește un drum de la intersecția_a la intersecție_b
      2. <c intersecție_a intersecție_b 1> - se blochează toate drumurile directe între intersecția_a și intersecție_b, indiferent de sens
      3. <c intersecție_a intersecție_b 2> - drumul între intersecția_a și intersecție_b devine bidirecțional. Dacă nu există drum între intersecția_a și intersecția_b (indiferent de sens), se vor adăuga muchii în ambele sensuri.
      4. <c intersecție_a intersecție_b 3> - se inversează sensul drumului dintre intersecția_a și intersecție_b (dacă era bidirecțional, rămâne bidirecțional; dacă nu există, se va ignora update-ul)
      5. <q intersecție_a intersecție_b 0> - query la care veți răspunde “y” dacă există un drum de la intersecție_a la intersecție_b, “n” în caz contrar
      6. <q intersecție_a intersecție_b 1> - query la care veți răspunde cu lungimea drumului minim de la intersecție_a la intersecție_b, dacă acesta există; se va afișa -1 în caz contrar;
      7. <q intersecție_a intersecție_b 2 intersecție_c> - query la care veți răspunde cu lungimea drumului minim de la intersecție_a la intersecție_b, trecând obligatoriu prin intersecție_c, dacă acesta există; -1 în caz contrar;
  7. Task 4:
    1. Un număr Q4, cu semnificația că acesta va fi numărul de curse, query-uri și informații despre șoferi specifice task-ului 4;
    2. Urmează Q4 linii care pot avea forma:
      1. <d nume_șofer intersecție>, cu semnificația că șoferul nume_șofer este online și se află în intersecția dată în input; dacă nume_șofer nu a mai fost online până acum, îl veți trata că pe un șofer nou;
      2. <b nume_șofer>, cu semnificația că șoferul nume_șofer își schimbă statusul în offline și nu mai poate accepta curse;
      3. <r start end rating>, cu semnificația că avem un client care pleacă din start și vrea să ajungă la end, iar în urma cursei va oferi șoferului care îl va transporta acel rating;
      4. <top_rating nr_șoferi> cu semnificația că va trebui să afișați primii nr_șoferi în funcție de rating, în ordine descrescătoare, dacă există mai mulți șoferi cu același rating, vor fi afișați în ordine lexicografică; dacă nu există suficienți șoferi, veți afișa toți șoferii;
      5. <top_dist nr_șoferi> cu semnificația că va trebui să afișați primii nr_șoferi în funcție de distanță totală parcursă, în ordine descrescătoare, dacă există mai mulți șoferi cu aceeași distanță parcursă, vor fi afișați în ordine lexicografică; dacă nu există suficienți șoferi, veți afișa toți șoferii; Obs.: la fiecare cursa distanța parcursă de șofer este d_cursă = d (loc_șofer, start) + d(start, end); distanță totală reprezintă suma tuturor distanțelor pe cursele efectuate până în momentul actual;
      6. <top_rides nr_șoferi> cu semnificația că va trebui să afișați primii nr_șoferi în funcție de numărul de curse efectuate, în ordine descrescătoare, dacă există mai mulți șoferi cu același număru de curse, vor fi afișați în ordine lexicografică; dacă nu există suficienți șoferi, veți afișa toți șoferii;
      7. <info nume_șofer> cu semnificația că va trebui să afișați pentru nume_șofer statisticile acestuia: locație, rating, nr_curse, distanță totală
  8. Task 5:
    1. O linie de forma <combustibil nume_șofer> cu semnificația că nume_șofer mai are la dispoziție cantitatea de combustibil dată;
    2. O linie de forma <nr_intersectii intersecție_1 intersecție_2 … > cu semnificația că nume_șofer vrea să ajungă în fiecare din intersecțiile date în inputul acestui task. De asemenea, poziția de start a șoferului este locația lui după efectuarea tuturor curselor de la Task 4;

Muchiile se pot repeta. De asemenea, muchiile și cursele pot fi de la un nod la el însuși.

Exemplu input

8 11
Berceni Chibrit Constitutiei Dorobanti Iancului Operei Romana Unirii
Chibrit Berceni
Berceni Romana
Chibrit Romana
Constitutiei Chibrit
Constitutiei Dorobanti
Iancului Romana
Romana Iancului
Operei Romana
Iancului Operei
Dorobanti Iancului
Iancului Dorobanti
3
Berceni Constitutiei
Operei Dorobanti
Chibrit Operei
3
Chibrit Operei
Romana Constitutiei
Berceni Dorobanti
10
c Romana Iancului 1
q Romana Dorobanti 0
c Constitutiei Dorobanti 3
q Iancului Constitutiei 1
q Constitutiei Romana 2 Berceni
c Constitutiei Romana 0
c Operei Romana 2
q Constitutiei Operei 1
c Operei Iancului 2
c Constitutiei Dorobanti 3
16
d Andrei Berceni
d Bogdan Romana
r Operei Dorobanti 4
r Operei Iancului 4
top_dist 6
d Mihaita Berceni
r Berceni Operei 3
b Bogdan
top_rating 2
info Mihaita
r Romana Constitutiei 5
r Berceni Unirii 4
r Constitutiei Romana 2
d Bogdan Constitutiei
r Constitutiei Iancului 5
info Bogdan
1 Bogdan
6 Operei Iancului Operei Romana Dorobanti Chibrit

Mai jos aveți reprezentarea grafului înainte și după modificările din task-ul 3. Vom indexa nodurile de la 0.

Inițial:

Final:

Date de ieșire

Obs.: Output-urile de la cele 5 task-uri vor fi scrise în fișiere separate(scrierea în fișiere e implementată în schelet).

Task1.out: Q1 linii de forma y/n în funcție de răspunsul la query. Pe prima linie se va află răspunsul la primul query, pe a două linie la al doilea, etc.

Task2.out: Q2 linii de forma <distanta_drum>, cu semnificația că pe prima linie se află răspunsul la primul query, pe a doua linie răspunsul la al doilea query, etc. Obs.: În cazul în care vi se cere lungimea unui drum indisponibil (nu avem drum între cele două intersecții), veți afișa -1.

Task3.out: Pe fiecare linie veți răspunde la query-urile întâlnite în inputul task-ului 3, asemănător task-urilor 1 și 2. Veți afișa y/n pentru query-urile de tip “există drum”, și un număr întreg pentru query-urile care cer lungimea drumului. În continuare în cazul unui drum indisponibil vom afișa -1 pentru lungimea sa.

Task4.out: Pe fiecare linie veți afișa output-ul query-urilor întâlnite în input-ul task-ului 4. Pentru query de tip top: <nume_1:valoare nume2:valoare … >, unde nume_i reprezintă numele șoferului i în top-ul cerut, iar valoare este valoarea cerută în top, și va fi un int în cazul curselor și distanței, și un float cu 2 zecimale în cazul mediei. În cazul query-ului tip info veți afișa <nume_șofer: locație rating curse distanță online/offline>, cu semnificația că locație este intersecția în care se află în momentul de față șoferul, rating este rating-ul mediu al acestuia, curse reprezintă numărul de curse încheiate de șofer, distanță reprezintă distanță totală parcursă de acesta pentru curse, iar online/offline este un tag care ne spune dacă șoferul în momentul de față este disponibil în aplicație sau nu. Dacă șoferul este offline locația acestuia va fi ultima intersecție în care s-a aflat înainte de a-și schimba statusul.

Task5.out: Veți afișa o singură linie de forma <intersecție_1 intersecție_2 … >, care va conține numele intersecțiilor ordonate după combustibilul rămas șoferului dacă ar merge din poziția lui actuală până în fiecare dintre intersecții. Intersecțiile în care nu poate ajunge (dacă nu are destul combustibil sau dacă nu e accesibilă) nu vor mai fi afișate. Dacă o intersecție apare de mai multe ori în input aceasta va fi afișată o singură dată.

Exemplu output

Task1.out
n
y
y
Task2.out
3
-1
3
Task3.out
n
2
3
2
Task4.out
Bogdan:6 Andrei:0
Bogdan:4.00 Andrei:3.00
Mihaita: Berceni 0.00 0 0 online
Destinatie inaccesibila
Soferi indisponibili
Bogdan: Iancului 4.33 3 8 online
Task5.out
Iancului Dorobanti Operei

Precizări

Toate structurile de date folosite trebuie să fie implementate generic, inclusiv graful ce va modela harta si hashtable-ul. O altfel de implementare va atrage depunctări.

NU puteți folosi map, unordered_map, set, unordered_set, priority_queue. De asemenea, nu puteți folosi sort (sau orice operatie de sortare/heap) din algorithm.

Puteți folosi următoarele containere din STL pentru a vă facilita implementarea: vector, list, stack, queue.

Checker

tema2-2019-checker.zip

Veți rezolva fiecare din cele 5 task-uri în funcția corespunzătoare din fișierul Solver.h aflat în arhivă. Pe lângă acestea puteți implementa orice funcții considerați că aveți nevoie.

Pe vmchecker veți face upload la o arhivă ce va conține fișierele sursă folosite în implementare, Makefile și README. Executabilul generat trebuie să se numească tema2.

ATENȚIE! Nu aveți voie să folosiți flag-uri de optimizare în Makefile (-O3, -O2, etc.)

Punctaj

  1. 80 de puncte pentru teste. Pentru a primi punctajul pe un test va trebui să treacă de verificarea cu Valgrind și să nu depășească timpul maxim de execuție.
  2. Cele 80 de puncte se impart astfel:
    1. Task1: 10p
    2. Task2: 10p
    3. Task3: 15p
    4. Task4: 35p
    5. Task5: 10p
  3. 10 puncte README
  4. 10 puncte pentru coding style, proporțional cu punctajul obținut pe teste
  5. O temă care obține 0p pe vmchecker este punctată cu 0.

Checkerul ține cont de timpul de rulare la fiecare test. La task4, unele teste sunt mai stricte. Încercați să folosiți structuri care vă avantajează din punctul de vedere al complexității. Gândiți-vă la ce structuri puteți folosi pentru a reduce timpul (de exemplu: a ține anumite elemente în ordine într-o listă e mai rapid decât a sorta mereu elementele dintr-o mulțime).

Nu copiați! Toate soluțiile vor fi verificate folosind o unealtă de detectare a plagiatului. În cazul detectării unui astfel de caz, atât plagiatorul cât și autorul original (nu contează cine care e) vor primi punctaj 0 pe toate temele!

De aceea, vă sfătuim să nu vă lăsați rezolvări ale temelor pe calculatoare partajate (la laborator etc), pe mail/liste de discuții/grupuri etc.

sd-ca/teme/tema2.txt · Last modified: 2019/04/25 23:05 by andrei.medar
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0