Úloha 4.3
Napíšte program, zdrojový kód, v jazyku C++ použitím štandardu C++17, ktorý realizuje nasledovnú činnosť.
Implementujte graf, ktorého hrany majú definovanú váhu, t.j. ováhovaný graf. Uzol grafu má označenie ‘label’ typu
string
. Hrana spájajúca dva uzly musí mať definovanú váhu typu int
. Hrany medzi uzlami nemajú orientáciu a tak
prechádzanie medzi uzlami môže byť oboma smermi.
Pre graf implementujte nasledovné metódy:
bool add_vertex(Vertex*, int*)
- Pridanie nového uzla do grafu. Metóda má byť ako public člen triedy Vertex. Prvý argument je pointer na uzol s ktorým chceme prepojenie vytvoriť. Druhý argument je váha hrany, ktorá bude vytvorená medzi týmito dvomi uzlami.int count(vector<string>*)
- Ak váha hrany predstavuje cenu, ktorú treba zaplatiť aby sme prešli po danej hrane na ďalší uzol, tak táto metóda vráti celkovú cenu cesty z uzla na uzol. Argument metódy je cesta prechádzania uzlov, kde prvok vektora je označenie (label) uzla. Ak taká cesta v grafe existuje metóda vráti jej celkovú cenu. Ak cesta neexistuje, t.j. neexistuje hrana, ktorá by prepojila dva uzly, ktoré sú za sebou definové vo vstupnom vektore, metóda vráti hodnotu-1
.
Príklady vstupov / výstupov programu
Ak máme graf s nasledujúcou štruktúrou:
Volanie funkcie pre výpočet celkovej ceny cesty (celkovej váhy) má nasledovné výsledky:
count({1,4,3}) == 8;
count({2,5,1,4}) == 14;
count({3,1,2,5,1}) == 18;
Rozbaľ pre ukážku riešenia
Ováhovaný neorientovaný graf implementovaný pomocou triedy Vertex
. Každý vrchol uchováva informácie o svojich susedoch a váhach hrán.
#include <iostream>
#include <unordered_map>
#include <vector>
#include <string>
using namespace std;
class Vertex {
private:
string label;
unordered_map<string, pair<Vertex*, int>> neighbors; // mapa: label suseda -> (pointer, váha)
public:
// Konštruktor
explicit Vertex(const string& lbl) : label(lbl) {}
// Getter pre label
string get_label() const {
return label;
}
// Pridanie hrany medzi this a druhým uzlom
bool add_vertex(Vertex* other, int* weight_ptr) {
if (!other || !weight_ptr) return false;
const string& other_label = other->get_label();
// Ak už je hrana medzi týmito uzlami, nepridávaj znova
if (neighbors.find(other_label) != neighbors.end()) {
return false;
}
// Pridaj hranu do oboch strán (graf je neorientovaný)
neighbors[other_label] = make_pair(other, *weight_ptr);
other->neighbors[label] = make_pair(this, *weight_ptr);
return true;
}
// Spočítanie ceny cesty podľa zoznamu labelov
int count(vector<string>* path) {
if (!path || path->empty()) return -1;
int total_cost = 0;
Vertex* current = this;
for (size_t i = 1; i < path->size(); ++i) {
const string& next_label = (*path)[i];
auto it = current->neighbors.find(next_label);
if (it == current->neighbors.end()) {
return -1; // neexistuje hrana medzi current a next_label
}
total_cost += it->second.second; // pripočítaj váhu hrany
current = it->second.first; // posuň sa na ďalší uzol
}
return total_cost;
}
};
int main() {
// Vytvorenie vrcholov
Vertex a("A");
Vertex b("B");
Vertex c("C");
Vertex d("D");
// Vytvorenie hrán s váhami
int ab = 5;
int ac = 3;
int bc = 2;
int cd = 4;
a.add_vertex(&b, &ab);
a.add_vertex(&c, &ac);
b.add_vertex(&c, &bc);
c.add_vertex(&d, &cd);
// Cesta: A -> C -> D
vector<string> path1 = {"A", "C", "D"};
cout << "Cost A->C->D: " << a.count(&path1) << endl; // očakávané: 3 + 4 = 7
// Cesta: A -> B -> C -> D
vector<string> path2 = {"A", "B", "C", "D"};
cout << "Cost A->B->C->D: " << a.count(&path2) << endl; // očakávané: 5 + 2 + 4 = 11
// Neexistujúca cesta: A -> D
vector<string> path3 = {"A", "D"};
cout << "Cost A->D: " << a.count(&path3) << endl; // očakávané: -1
return 0;
}
Vysvetlenie
- Každý
Vertex
obsahuje mapu svojich susedov (unordered_map<string, pair<Vertex*, int>>
), kde:string
jelabel
suseda,Vertex*
je pointer na suseda,int
je váha hrany.
- Metóda
add_vertex()
zabezpečuje pridanie obojstrannej hrany (graf je neorientovaný). - Metóda
count()
počíta cenu cesty cez daný zoznam názvov uzlov – ak niektorá hrana chýba, vráti-1
.
Ukážkový výstup
Cost A->C->D: 7
Cost A->B->C->D: 11
Cost A->D: -1
ASCII vizualizácia
[A]
/ \
5 / \ 3
/ \
[B]--2--[C]--4--[D]