import platform
platform.platform()
platform.python_version()
import warnings
warnings.filterwarnings("ignore")
import networkx as nx
nx.__version__
from pylab import *
%matplotlib inline
import matplotlib as plt
plt.__version__
import DSTG
K23=nx.complete_bipartite_graph(2,3)
nx.check_planarity(K23)
nx.check_planarity(K23)[1].get_data()
nx.draw(K23,with_labels=True,pos={0:[0,2],1:[0,0],2:[-1,1],3:[1,1],4:[0,1]},node_color='y')
$K_{3,3}$ nije planarni graf
K33=nx.complete_bipartite_graph(3,3)
nx.check_planarity(K33)
K5=nx.complete_graph(5)
nx.check_planarity(K5)
P=nx.petersen_graph()
nx.check_planarity(P)
K4=nx.complete_graph(4)
nx.check_planarity(K4)
nx.draw(K4,with_labels=True,pos={0:[0,0],1:[1,1],2:[2,0],3:[1,0.4]},node_color='y')
Platonova tijela su planarni grafovi.
kocka=nx.cubical_graph()
nx.check_planarity(kocka)
Neko ravninsko smještenje
$\nu=8,\ \varepsilon=12,\ \Phi=6,\ \nu-\varepsilon+\Phi=2$
figure(figsize=(4,4))
nx.draw(kocka,pos=DSTG.PLATON['KOCKA'],with_labels=True,node_color='y')
tetraedar=nx.tetrahedral_graph()
nx.check_planarity(tetraedar)
Neko ravninsko smještenje
$\nu=4,\ \varepsilon=6,\ \Phi=4,\ \nu-\varepsilon+\Phi=2$
figure(figsize=(4,4))
nx.draw(tetraedar,pos=DSTG.PLATON['TETRAEDAR'],with_labels=True,node_color='y')
oktaedar=nx.octahedral_graph()
nx.check_planarity(oktaedar)
Neko ravninsko smještenje
$\nu=6,\ \varepsilon=12,\ \Phi=8,\ \nu-\varepsilon+\Phi=2$
figure(figsize=(4,4))
nx.draw(oktaedar,pos=DSTG.PLATON['OKTAEDAR'],with_labels=True,node_color='y')
dodekaedar=nx.dodecahedral_graph()
nx.check_planarity(dodekaedar)
Neko ravninsko smještenje
$\nu=20,\ \varepsilon=30,\ \Phi=12,\ \nu-\varepsilon+\Phi=2$
figure(figsize=(5,5))
nx.draw(dodekaedar,pos=DSTG.PLATON['DODEKAEDAR'],with_labels=True,node_color='y')
ikozaedar=nx.icosahedral_graph()
nx.check_planarity(ikozaedar)
Neko ravninsko smještenje
$\nu=12,\ \varepsilon=30,\ \Phi=20,\ \nu-\varepsilon+\Phi=2$
figure(figsize=(6,6))
nx.draw(ikozaedar,pos=DSTG.PLATON['IKOZAEDAR'],with_labels=True,node_color='y')
U tablici se nalazi popis od 10 studentica zajedno s kolegijima koje su odabrale.
studentica | odabrani kolegiji |
Marija | Fizika, Matematika, Engleski |
Janja | Fizika, Geografija, Ekonomija |
Ivana | Geografija, Poslovanje |
Ana | Statistika, Ekonomija |
Lana | Matematika, Poslovanje |
Sandra | Fizika, Geografija |
Danijela | Poslovanje, Statistika |
Katarina | Matematika, Geografija |
Petra | Fizika, Plivanje, Statistika |
Dijana | Fizika, Ekonomija, Plivanje |
Neki od kolegija se mogu istovremeno predavati. Međutim, želimo li svakoj od studentica omogućiti nesmetano slušanje svih kolegija koje je odabrala, koliko najmanje različitih vremenskih termina predavanja moramo staviti u raspored?
Formiramo graf u kojemu su vrhovi svi spomenuti kolegiji, a dva vrha su spojena bridom ako i samo ako postoji studentica koja je upisala oba pripadna kolegija. Najmanji broj termina je tada jednak kromatskom broju tog grafa.
G1=nx.Graph({"fizika":["matematika","engleski","geografija","ekonomija","plivanje","statistika"],
"matematika":["engleski","poslovanje","geografija"],
"geografija":["ekonomija","poslovanje"],
"statistika":["ekonomija","poslovanje","plivanje"],
"ekonomija":["plivanje"]})
figure(figsize=(6.5,6.5))
nx.draw_circular(G1,with_labels=True,node_color='y',node_size=5000,edgecolors='k')
Kromatski broj grafa je 4 pa su potrebna najmanje 4 različita termina.
DSTG.kromatski_broj(G1)
Jedan mogući razmještaj predmeta u termine (dva predmeta se izvode u istom terminu ako i samo ako imaju istu boju).
DSTG.bojanje_vrhova(G1)
želimo li to prikazati vizualno na samom grafu
figure(figsize=(6.5,6.5))
DSTG.obojani_vrhovi(G1,nx.circular_layout(G1),5000)
list(nx.enumerate_all_cliques(G1))
list(nx.find_cliques(G1))
nx.graph_number_of_cliques(G1)
nx.graph_clique_number(G1)
nx.node_clique_number(G1)
nx.number_of_cliques(G1)
nx.cliques_containing_node(G1,['fizika','matematika'])
Pohlepno bojanje sa slučajnim rasporedom vrhova ne mora uvijek dati bojanje vrhova s minimalnim brojem boja.
for i in range(100):
rj=nx.greedy_color(G1,'random_sequential')
if max(rj.values())>3:
print('korak: ',i)
print(rj)
break
Welsh-Powellov algoritam
nx.greedy_color(G1,'largest_first')
Brelazov algoritam
nx.greedy_color(G1,'DSATUR')
Devet televizijskih postaja je smješteno u devet gradova $A,$ $B,$ $C,$ $D,$ $E,$ $F,$ $G,$ $H,$ $I$ čije su međusobne udaljenosti u kilometrima dane u tablici.
A | B | C | D | E | F | G | H | |
B | 85 | |||||||
C | 137 | 165 | ||||||
D | 123 | 39 | 205 | |||||
E | 164 | 132 | 117 | 171 | ||||
F | 105 | 75 | 235 | 92 | 201 | |||
G | 134 | 191 | 252 | 223 | 298 | 177 | ||
H | 114 | 77 | 113 | 117 | 54 | 147 | 247 | |
I | 132 | 174 | 22 | 213 | 138 | 237 | 245 | 120 |
Svakoj televizijskoj postaji se treba dodijeliti kanal preko kojeg će emitirati svoj program. Zbog nesmetanog emitiranja programa, televizijskim postajama koje su na udaljenosti manjoj od 150 km treba dodijeliti različite kanale. Televizijske postaje koje su na udaljenosti većoj od 150 km mogu nesmetano emitirati svoje programe preko istog kanala.
Konstruiramo graf u kojemu će vrhovi biti televizijske postaje, a dvije televizijske postaje su spojene bridom ako i samo ako su na udaljenosti manjoj od 150 km. Tada je minimalni broj kanala jednak kromatskom broju konstruiranog grafa.
G2=nx.Graph({"A":["B","C","D","F","G","H","I"],"B":["D","E","F","H"],"C":["E","H","I"],
"D":["F","H"],"E":["H","I"],"F":["H"],"H":["I"]})
figure(figsize=(6.5,6.5))
nx.draw_circular(G2,with_labels=True,node_color='y',edgecolors='k')
Kromatski broj grafa je 5 pa je potrebno minimalno 5 različitih kanala.
DSTG.kromatski_broj(G2)
Jedno bojanje vrhova s minimalnim brojem boja. Na istom kanalu mogu emitirati svoje programe one televizijske postaje kojima je dodijeljena ista boja.
DSTG.bojanje_vrhova(G2)
želimo li to prikazati vizualno na samom grafu
figure(figsize=(6.5,6.5))
DSTG.obojani_vrhovi(G2,nx.circular_layout(G2))
list(nx.enumerate_all_cliques(G2))
list(nx.find_cliques(G2))
nx.graph_number_of_cliques(G2)
nx.graph_clique_number(G2)
nx.node_clique_number(G2)
nx.number_of_cliques(G2)
nx.cliques_containing_node(G2,['A','E','H'])
Promatrani graf nije planarni jer sadrži podgraf $K_5$ koji nije planarni.
nx.check_planarity(G2)
Pogledajmo kako još pohlepna bojanja rade na promatranom grafu. Pokrenite implementirane algoritme za pohlepno bojanje na zadanom grafu 10 000 puta i obratite pažnju da li uvijek daju bojanje vrhova s minimalnim brojem boja.
Kako Welsh-Powellov i Brelazov algoritam nisu randomizirani u networkx modulu, koristimo vlastite implementacije koje su randomizirane.
for k in range(60):
rj=nx.greedy_color(G2,'random_sequential')
print(rj,max(rj.values())+1)
for k in range(20):
print(DSTG.Welsh_Powell(G2))
for k in range(20):
print(DSTG.Brelaz(G2))
Pokažite da Brelazov i Welsh-Powellov algoritam ne daju uvijek bojanje vrhova s minimalnim brojem boja u grafu
G3=nx.Graph({"v1":["v2","v5","v9"],"v2":["v3","v8"],"v3":["v4","v7"],"v4":["v6","v9"],
"v5":["v6","v7"],"v6":["v8"],"v7":["v8","v9"],"v8":["v9"]})
Kromatski broj zadanog grafa je 3.
DSTG.kromatski_broj(G3)
Vidimo da nam se dogodilo da u 20 izvođenja Brelazov i Welsh-Powellov algoritam nisu uvijek dali bojanje vrhova s minimalnim brojem boja (ukoliko se to ne dogodi u prvih 20 puta, ponovite algoritme više od 20 puta).
for k in range(20):
print(DSTG.Welsh_Powell(G3))
for k in range(20):
print(DSTG.Brelaz(G3))
Odredite kromatski i bridno kromatski broj grafa
G4=nx.Graph({1:[2,4,5,6],2:[3,5,7],3:[4,5,6,7],4:[5,6,7]})
G4poz={1:[0,0],2:[3,0],3:[3,3],4:[0,3],5:[1.5,1.5],6:[-1,4],7:[4,4]}
nx.draw(G4,pos=G4poz,with_labels=True,node_color='y')
Kromatski broj grafa je 3.
DSTG.kromatski_broj(G4)
Jedno bojanje vrhova s minimalnim brojem boja
DSTG.bojanje_vrhova(G4)
DSTG.obojani_vrhovi(G4,G4poz)
Pogledajmo kako se ponašaju pohlepna bojanja na ovom grafu. Izvršite svaki od tih algoritama 10 000 puta na zadanom grafu i donesite neki zaključak na temelju tog eksperimenta.
for k in range(20):
rj=nx.greedy_color(G4,'random_sequential')
print(rj,max(rj.values())+1)
for k in range(20):
print(DSTG.Welsh_Powell(G4))
for k in range(20):
print(DSTG.Brelaz(G4))
Bridno kromatski broj grafa je 5.
DSTG.bridno_kromatski_broj(G4)
Jedno bojanje bridova s minimalnim brojem boja.
DSTG.bojanje_bridova(G4)
Vizualizacija obojenih bridova na slici
DSTG.obojani_bridovi(G4,G4poz)
Implementirane algoritme za pohlepno bojanje vrhova grafa možemo primijeniti i za pohlepno bojanje bridova grafa. Ukoliko želimo pronaći neko pohlepno bojanje bridova grafa $G$, tada naše implementirane algoritme moramo primijeniti na linijskom grafu grafa $G$, tj. na grafu $L(G)$. Jasno, pohlepno bojanje bridova grafa općenito ne daje bojanje bridova s minimalnim brojem boja.
G4line=nx.line_graph(G4)
Ovdje je svaki od pohlepnih algoritama primijenjen samo 20 puta na promatranom grafu. Primijenite svaki od tih algoritama 10 000 puta na zadanom grafu i donesite na temelju toga neki zaključak.
for k in range(20):
rj=nx.greedy_color(G4line,'random_sequential')
print(rj,max(rj.values())+1)
print()
for k in range(20):
print(DSTG.Welsh_Powell(G4line))
print()
for k in range(20):
print(DSTG.Brelaz(G4line))
print()
Osam studentica FOI-a treba posuditi određene knjige u knjižnici i svaku knjigu posuđuju na tjedan dana i pritom mogu posuditi samo jednu knjigu jer gradivo je zahtjevno i teško je dvije knjige proučiti u tjedan dana. U tablici je dani popis studentica kao i knjige koje su potrebne pojedinim studenticama.
studentica | knjige |
Emina | $K_1$, $K_2$, $K_3$ |
Maja | $K_2$, $K_4$, $K_5$, $K_6$ |
Ana | $K_2$, $K_3$, $K_5$, $K_7$ |
Marina | $K_3$, $K_5$ |
Sandra | $K_1$, $K_6$, $K_7$ |
Sanja | $K_2$, $K_4$, $K_6$ |
Martina | $K_4$, $K_5$, $K_7$ |
Ines | $K_3$, $K_6$ |
Nakon koliko minimalno tjedana će sve studentice posuditi sve knjige koje trebaju? Napravite za svaku studenticu jedan takav raspored posuđivanja knjiga po tjednima koji traje minimalni broj tjedana. Pritom pretpostavljamo da knjižnica ima samo po jedan primjerak pojedine knjige.
Konstruiramo bipartitni graf. U jednoj particiji su studentice, a u drugoj knjige. Pojedina studentica je spojena bridovima sa svim knjigama koje treba. Minimalni broj tjedana je tada jednak bridno kromatskom broju grafa. Svaka boja predstavlja tjedne.
G5=nx.Graph({"Emina":["K1","K2","K3"],"Maja":["K2","K4","K5","K6"],
"Ana":["K2","K3","K5","K7"],"Marina":["K3","K5"],
"Sandra":["K1","K6","K7"],"Sanja":["K2","K4","K6"],
"Martina":["K4","K5","K7"],"Ines":["K3","K6"]})
G5pos=nx.bipartite_layout(G5,nx.bipartite.sets(G5)[0],align='horizontal')
figure(figsize=(8,5))
nx.draw(G5,G5pos,with_labels=True,node_color='y',node_size=2000)
Bridno kromatski broj grafa je jednak 4 pa će nakon minimalno 4 tjedna sve studentice posuditi sve knjige koje trebaju.
DSTG.bridno_kromatski_broj(G5)
jedno bojanje bridova s minimalnim brojem boja
DSTG.bojanje_bridova(G5)
Vizualizacija bojanja bridova na slici
figure(figsize=(8,5))
DSTG.obojani_bridovi(G5,G5pos,velicina_vrha=2000)
DSTG.raspored_termina(G5,["1. tjedan","2. tjedan","3. tjedan","4. tjedan"])
DSTG.raspored_termina(G5,["1. tjedan","2. tjedan","3. tjedan","4. tjedan"],permutacija=[3,2,1,4])
Želimo li raspored po knjigama, tj. da znamo kod koje se studentice u pojedinom tjednu nalazi pojedina knjiga
DSTG.raspored_termina(G5,["1. tjedan","2. tjedan","3. tjedan","4. tjedan"],2)
DSTG.raspored_termina(G5,["1. tjedan","2. tjedan","3. tjedan","4. tjedan"],2,[3,4,2,1])
Želimo izraditi raspored posjeta pacijenata $P=\{u,v,z,x\}$ koji se trebaju pregledati kod specijalista $S=\{a,b,c,d,e,f,g\}$. Pri tome pacijent treba posjetiti određenog specijalistu kako je dano u tablici susjednosti.
♦ | $a$ | $b$ | $c$ | $d$ | $e$ | $f$ | $g$ |
$u$ | 1 | 1 | 0 | 0 | 0 | 0 | 1 |
$v$ | 0 | 1 | 1 | 0 | 1 | 0 | 0 |
$z$ | 1 | 0 | 0 | 1 | 0 | 1 | 0 |
$x$ | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
Treba napraviti raspored posjeta pacijenata pojedinom specijalistu, ali i raspored za specijaliste da znaju u kojem terminu im dolazi pojedini pacijent. Svaki pregled traje pola sata i počinje se s radom u 8:00h.
Konstruiramo bipartitni graf. U jednoj particiji su pacijenti, a u drugoj specijalisti. Pojedini pacijent je spojena bridovima sa svim specijalistima koje treba posjetiti. Minimalni broj termina je tada jednak bridno kromatskom broju grafa. Svaka boja predstavlja pojedini termin od pola sata.
G6=nx.Graph({"u":["a","b","g"],"v":["b","c","e"],"z":["a","d","f"],"x":["e","f","g"]})
G6pos=nx.bipartite_layout(G6,nx.bipartite.sets(G6)[0],align='horizontal')
nx.draw(G6,G6pos,with_labels=True,node_color='y')
Bridno kromatski broj grafa je jednak 3 pa su potrebna minimalno tri različita termina u rasporedu.
DSTG.bridno_kromatski_broj(G6)
jedno bojanje bridova s minimalnim brojem boja
DSTG.bojanje_bridova(G6)
Vizualizacija bojanja bridova na slici
DSTG.obojani_bridovi(G6,G6pos)
jedan mogući raspored termina za liječnike
DSTG.raspored_termina(G6,["8:00h","8:30h","9:00h"],2)
jedan mogući raspored termina za pacijente
DSTG.raspored_termina(G6,["8:00h","8:30h","9:00h"])
možemo malo promijeniti termine
DSTG.raspored_termina(G6,["8:00h","8:30h","9:00h"],2,[2,3,1])
DSTG.raspored_termina(G6,["8:00h","8:30h","9:00h"],1,[2,3,1])
Pet neudatih djevojaka ima određeni broj neoženjenih prijatelja kako je prikazano u sljedećoj tablici.
djevojke | neoženjeni prijatelji |
Sandra | Ivan, Miroslav, Marijan, Danijel |
Maja | Miroslav, Franjo |
Ana | Ivan, Marijan |
Emina | Marijan, Danijel |
Ines | Miroslav, Marijan |
Konstruiramo bipartitni graf. U jednoj particiji su djevojke, a u drugoj neoženjeni prijatelji. Svaka djevojka je u grafu susjedna samo sa svojim prijateljima.
G7=nx.Graph({"Sandra":["Ivan","Miroslav","Marijan","Danijel"],"Maja":["Miroslav","Franjo"],
"Ana":["Ivan","Marijan"],"Emina":["Marijan","Danijel"],"Ines":["Miroslav","Marijan"]})
G7pos=nx.bipartite_layout(G7,nx.bipartite.sets(G7)[0],align='horizontal')
nx.draw(G7,G7pos,with_labels=True,node_color='y',node_size=2800)
Moguće je svakoj djevojci ostvariti njezinu želju zato jer najveće sparivanje u promatranom bipartitnom grafu ima ukupno 5 bridova pa je to ujedno i savršeno sparivanje.
nx.max_weight_matching(G7, maxcardinality=True)
najveće sparivanje prikazano na grafu
figure(figsize=(10,6))
DSTG.najvece_sparivanje_graf(G7,G7pos,velicina_vrha=2800)
nx.maximal_matching(G7)
figure(figsize=(10,6))
DSTG.maksimalno_sparivanje_graf(G7,G7pos,velicina_vrha=2800)
figure(figsize=(10,6))
DSTG.maksimalno_sparivanje_graf(G7,G7pos,M=[('Maja','Miroslav')],velicina_vrha=2800)
drugi dio zadatka
Ako se Maja udala za Miroslava, tada će Franjo sigurno ostati neoženjen jer se on jedino sviđao Maji. Dakle, Maja će svojom udajom za Miroslava, sigurno unesrećiti neku od preostalih djevojaka u smislu da se neka od njih neće moći udati za neku od svojih simpatija.
Ukoliko se Maja uda za Miroslava, preostale djevojke osim Sandre je moguće spasiti na sljedeći način: Ines se udaje za Marijana, Emina za Danijela, Ana za Ivana. U tom slučaju Sandra ima mogućnost da se uda za Franju (iako on nije njezina simpatija) ili može ostati slobodna cura. :-)
Isprobajmo i našu funkciju random_maximal_matching koja će tražiti maksimalno sparivanje koje sadrži brid {Maja, Miroslav}. Vidimo da u 20 pokretanja ove funkcije čak možemo i dvije djevojke razočarati, tj. postoji maksimalno sparivanje sa samo tri brida koje sadrži brid {Maja, Miroslav}. Nadalje, moguće je da u svakom od tih maksimalnih sparivanja Sandra nikad nije razočarana. Naime, postoji puno bridova s kojima je Sandra susjedna pa je zato i velika vjerojatnost da će naša randomizirana funkcija odabrati ranije neki od tih bridova.
for k in range(20):
print(DSTG.random_maximal_matching(G7,[('Maja','Miroslav')]))
Ako nam se ne pojavi maksimalno sparivanje bez Sandre koje sadrži brid {Maja, Miroslav} u prvih 20 pokretanja, možemo probati algoritam pokrenuti više od 20 puta i čekati tako dugo dok se eventualno ne pojavi takvo sparivanje.
for k in range(100):
spar=DSTG.random_maximal_matching(G7,[('Maja','Miroslav')])
prvi=map(lambda x:x[0],spar)
drugi=map(lambda x:x[1],spar)
if not(('Sandra' in prvi) or ('Sandra' in drugi)):
print(k+1,'. korak',spar)
break
elif k==99:
print('Sandra ne odustaje od udaje. :-)')
ili još bolje, izbrišemo sve bridove koji su susjedni sa vrhom 'Sandra' i tada relativno brzo dobijemo željeno sparivanje
bridoviSandra=list(filter(lambda x: (x[0]=='Sandra') or (x[1]=='Sandra'),G7.edges()))
G7.remove_edges_from(bridoviSandra)
for k in range(10):
print(DSTG.random_maximal_matching(G7,[('Maja','Miroslav')]))
Nina, Danijela, Sandra, Iva, Renata, Mirela i Marija poznaju neke od mladića $M_1,\ldots,M_8$. Preciznije, Nina poznaje mladiće $M_1$, $M_2$ i $M_6$. Danijela poznaje $M_2$, $M_3$ i $M_6$. Sandra poznaje $M_1$, $M_3$ i $M_5$. Iva poznaje $M_4$, $M_7$ i $M_8$. Renata poznaje $M_1$, $M_5$ i $M_6$. Mirela poznaje $M_1$, $M_3$ i $M_6$. Marija poznaje $M_3$, $M_5$ i $M_6$.
Konstruiramo bipartitni graf. U jednoj particiji su djevojke, a u drugoj mladići. Djevojke su susjedne samo s onim mladićima koje poznaju.
G8=nx.Graph({"Nina":["M1","M2","M6"],"Danijela":["M2","M3","M6"],"Sandra":["M1","M3","M5"], "Iva":["M4","M7","M8"],
"Renata":["M1","M5","M6"],"Mirela":["M1","M3","M6"],"Marija":["M3","M5","M6"]})
G8pos={"Nina":[0,0],"Danijela":[2,0],"Sandra":[4,0],"Iva":[6,0],"Renata":[8,0],"Mirela":[10,0],"Marija":[12,0],
"M1":[-0.5,3],"M2":[1.5,3],"M3":[3.5,3],"M4":[5.5,3],"M5":[7.5,3],"M6":[9.5,3],"M7":[11.5,3],"M8":[13.5,3]}
figure(figsize=(12,5.5))
ylim(-0.4,3.5)
nx.draw(G8,G8pos,with_labels=True,node_color='y',node_size=2800)
Nije moguće ispuniti želje svim djevojkama jer najveće sparivanje u grafu ima samo 6 elemenata, a djevojaka je ukupno 7.
nx.max_weight_matching(G8, maxcardinality=True)
Kada ručno rješavamo, trebamo se pozvati na Hallov teorem.
Naime, ako uzmemo, $T\subseteq X$, $T=\{\text{Nina}, \text{Danijela}, \text{Sandra}, \text{Renata}, \text{Mirela}, \text{Marija}\}$, tada je $S(T)=\{M_1, M_2, M_3, M_5, M_6\}$. No, tada je kardinalni broj skupa $S(T)$ strogo manji od kardinalnog broja skupa $T$ pa prema Hallovom teoremu ne postoji sparivanje koje zasićuje svaki vrh iz $X$.
figure(figsize=(12,5.5))
DSTG.najvece_sparivanje_graf(G8,G8pos,velicina_vrha=2800,slika=[0.05,0.12])
Osam djevojaka su odlučile otići tjedan dana na veslanje u predivnu prirodu. Kako na tom mjestu u toj predivnoj prirodi postoje samo četiri čamca u koje stanu po dvije djevojke, one se moraju podijeliti u parove. Međutim, neke od djevojaka ne žele veslati zajedno iz nekih privatnih razloga. Sljedeća tablica nam razotkriva koje djevojke žele zajedno veslati. Ako neke dvije djevojke žele zajedno veslati, u tablici je odgovarajuće mjesto označeno s 1. Ako je neko mjesto u tablici označeno s 0, tada odgovarajuće djevojke ne žele zajedno veslati.
♦ | Marija | Janja | Ivana | Sandra | Danijela | Katarina | Petra | Dijana |
Marija | ♦ | 0 | 0 | 0 | 1 | 1 | 0 | 1 |
Janja | 0 | ♦ | 0 | 1 | 1 | 1 | 0 | 0 |
Ivana | 0 | 0 | ♦ | 1 | 0 | 0 | 1 | 1 |
Sandra | 0 | 1 | 1 | ♦ | 0 | 0 | 1 | 0 |
Danijela | 1 | 1 | 0 | 0 | ♦ | 0 | 0 | 1 |
Katarina | 1 | 1 | 0 | 0 | 0 | ♦ | 0 | 1 |
Petra | 0 | 0 | 1 | 1 | 0 | 0 | ♦ | 0 |
Dijana | 1 | 0 | 1 | 0 | 1 | 1 | 0 | ♦ |
Konstruirat ćemo graf u kojemu će vrhovi biti djevojke, a dva vrha su spojena bridom jedino ako pripadne djevojke žele zajedno veslati. Tada u dobivenom grafu želimo naći savršeno sparivanje ukoliko ono postoji.
M=matrix([[0,0,0,0,1,1,0,1], [0,0,0,1,1,1,0,0], [0,0,0,1,0,0,1,1], [0,1,1,0,0,0,1,0],
[1,1,0,0,0,0,0,1], [1,1,0,0,0,0,0,1], [0,0,1,1,0,0,0,0], [1,0,1,0,1,1,0,0]])
G9=nx.from_numpy_matrix(M)
rj=dict(zip(range(8),['Marija','Janja','Ivana','Sandra','Danijela','Katarina','Petra','Dijana']))
G9=nx.relabel_nodes(G9,rj)
Uočite da G9 nije bipartitni graf jer sadrži cikluse neparnih duljina.
nx.is_bipartite(G9)
figure(figsize=(5,5))
nx.draw_circular(G9,with_labels=True,node_color='y',node_size=2800)
Kako najveće sparivanje ima 4 brida, a graf ima 8 vrhova, to sparivanje je ujedno i savršeno sparivanje. Stoga se djevojke mogu grupirati u parove za veslanje tako da svaka djevojka vesla s nekom od djevojaka s kojom zaista želi veslati.
nx.max_weight_matching(G9, maxcardinality=True)
figure(figsize=(7,7))
DSTG.najvece_sparivanje_graf(G9,nx.circular_layout(G9),velicina_vrha=2800,slika=[0.1,0.12])
No, nakon svađe situacija postaje ozbiljnija :-)
G9.remove_edges_from([('Dijana','Ivana'),('Janja','Sandra')])
figure(figsize=(5,5))
nx.draw_circular(G9,with_labels=True,node_color='y',node_size=2800)
Kako najveće sparivanje ima samo 3 brida u grafu od 8 vrhova, zaključujemo da u zadanom grafu nema savršenog sparivanja pa se u ovom slučaju djevojke ne mogu rasporediti u parove za veslanje tako da svaka djevojka vesla s nekom od djevojaka s kojom zaista želi veslati.
nx.max_weight_matching(G9, maxcardinality=True)
Jedno najveće sparivanje u kojemu su Sandra i Danijela ostale bez svojeg para pa bi bile prisiljene zajedno veslati, iako one ne žele zajedno veslati.
figure(figsize=(7,7))
DSTG.najvece_sparivanje_graf(G9,nx.circular_layout(G9),velicina_vrha=2800,slika=[0.1,0.12])