Epidemiologija

Končno smo izvedeli, kaj je bilo narobe septembra, da se je potem ta reč tako razširila. Takole je bilo.

  • Ana je bila okužena in se je videla z Berto v šoli, na sprehodu in na žurki. Zato je zbolela še Berta.
  • Ana je osrečila tudi Cilko: bili sta na sprehodu in v trgovini.
  • Berta je po tem, ko je bila že okužena, šla na sprehod z Dani. Tako jo je fasala Dani.
  • Okužena Berta je bila v šoli in na žurki z Emo. In ... seveda.
  • Dani je okužila Helgo, ker je bila z njo v šoli in na sprehodu.

Vse to in še več je na sliki.

V Pythonu pa bo to zapisano s slovarjem slovarjev množic. Razmisli in razumi.

stiki = {"Ana": {"Berta": {"šola", "sprehod", "žurka"},
                 "Cilka": {"sprehod", "trgovina"}},
          "Berta": {"Dani": {"sprehod"},
                    "Ema": {"šola", "žurka"}},
          "Cilka": {"Fanči": {"sprehod"},
                    "Greta": {"sprehod"}},
          "Dani": {"Helga": {"sprehod", "šola"}},
          "Ema": {"Iva": {"žurka"},
                  "Jana": {"šola", "žurka"}},
          "Greta": {"Klara": {"šola", "žurka"},
                    "Liza": {"trgovina", "šola", "žurka"},
                    "Micka": {"trgovina", "žurka"}},
          "Liza": {"Nina": {"trgovina", "šola"},
                   "Olga": {"šola"}}
          }

Vse funkcije, ki jih bo potrebno napisati bodo rekurzivne. Globalne spremenljivke so sicer grda reč, tu pa bodo funkcije, zato da bodo njihovi argumenti jasnejši, brale podatke kar iz globalne spremenljivke z imenom stiki. (Tako kot smo na predavanjih brali iz globalne spremenljivke otroci, ne da bi razmišljali o tem grehu.)

Funkcije morajo biti splošne: ne smete predpostaviti, da imajo osebe natančno takšna imena in da hodijo le v šolo, trgovino, na sprehode in žurke. Da bo res tako, bodo testi vaše funkcije najprej testirali s temi imeni in aktivnostmi, nato pa bodo ta imena zamenjali še z naključno generiranimi nizi.

Obvezne naloge

  • Napiši funkcijo stevilo_okuzenih(oseba), ki prejme ime osebe in vrne število vseh, ki so okuženi zaradi te osebe (in še to osebo zraven).

    Klic stevilo_okuzenih("Berta") vrne 6, ker so po Bertini zaslugi okužene Dani, Ema, Helga, Iva, Jana in še Berta sama (sama si je kriva, kaj pa je žurala z Ano).

    (Da, tu zadošča gledati zgolj ključe "podslovarjev", ne pa vrednosti. Pomembno je le, da je bila Ana v stiku z Berto in Cilko; kaj so počele, pa ni pomembno.)

  • Napiši funkcijo rekord(oseba), ki vrne največje število oseb, ki jih je okužila posamezna oseba izmed tistih, ki so bile okužene zaradi osebe, podane kot argument. Tudi tu upoštevaj tudi osebo samo.

    Klic rekord("Ana") vrne 3, saj je med Aninimi okuženci Greta, ki je okužila tri osebe. Prav tako klic rekord("Greta") vrne 3, zaradi Grete same. Klic rekord("Berta") pa vrne 2, zaradi Berte ali Eme. Klic rekord("Dani") vrne 1 in klic rekord("Helga") vrne 0.

Dodatne naloge

V gornjih nalogah nas ni zanimal razlog okužbe. Če želimo pomagati vladi uvesti pametna pravila, pa se bo potrebno poglobiti še v razloge.

  • Najprej nas zanima, kako nevarna je posamezna aktivnost. Zato napiši funkcijo nevarnost(oseba, razlog), ki vrne število okužb, ki jih je (neposredno ali posredno) povzročila oseba, pri katerih je bil eden od razlog (ali edini razlog) razlog, ki je podan kot argument. Grafično, funkcija mora prešteti, koliko povezav v drevesu pod podano osebo je takšne barve, ki ustreza razlogu.

    Klic nevarnost("Ana", "trgovina") vrne 4, ker so pod Ano štiri rjave povezave.

    Tu upoštevaj, da se okužbe širijo le navzdol. Če bi se okužba začela pri Greti, ta vseeno ne more okužiti Cilke, ker se je z njo (recimo) sprehajala, še preden je zbolela.

  • A to mogoče ni to, kar nas v resnici zanima. Zanima nas, koliko bi bilo okuženih, če bi se bilo možno okuževati le na določen način. Vzemimo, da se da okužiti le v trgovini. Če bi okužbo poleti (ponovno) uvozila le Ana, bi bili v tem primeru bolni le dve, Ana in Cilka. Do Lize, Micke in Nine ta okužba ne bi prišla, saj je povezava med Cilko in Greto zelena (sprehod). Če pa bi bila nevarna šola (in okužbo spet začnemo pri Ani), zbolijo štiri (Ana, Berta, Ema in Jana). Če bi bili nevarni sprehodi, jih zboli sedem (Ana, Berta, Cilka, Dani, Fanči, Greta in Helga).

    Napiši torej funkcijo okuzbe_zaradi(oseba, razlog), ki prejme osebo, ki začne okužbo in razlog širjenja okužbe, ki nas zanima. Vrniti mora število okuženih, kot ga kažejo gornji primeri.

    Klic okuzbe_zaradi("Ana", "šola") vrne 4.

  • Po ponovnem premisleku pa vidimo, da je narobe tudi to. V bistvu nas zanima število okužb, do katerega bo prišlo, če prepovemo določeno množico aktivnosti. Če, recimo, prepovemo sprehajanje in nakupovanje, okužba pa se začne pri Ani, bo okuženih pet oseb, namreč Ana, Berta, Ema, Iva in Jana. Če prepovemo le sprehajanje, pa bo pravzaprav podobno -- okuženih bo šest oseb, namreč prejšnjih pet in še Cilka zraven.

    Napiši funkcijo okuzbe_brez(oseba, prepovedane), ki prejme ime osebe in množico prepovedanih aktivnosti. Funkcija vrne število okuženih.

    Klic okuzbe_brez("Ana", {"sprehod", "trgovina"}) vrne 5.

Še par nalog za vajo

Za te funkcije ni priloženih testov.

  • Poleg funkcije stevilo_okuzenih napiši še funkcijo seznam_okuzenih, ki namesto števila okuženih vrne seznam.

  • Poleg funkcije rekord napiši funkcijo zlati_prinasalec, ki namesto največjega števila okuženih vrne ime tistega, ki je okužil največ ljudi. Če je takšnih več, vrne prvega po abecedi.

  • Poleg funkcije stevilo_okuzenih napiši funkcijo stevilo_zrtev, ki vrne število žrtev te osebe. Torej 1 manj kot bi vrnila funkcija stevilo_okuzenih. Funkcije ne napiši tako, da le pokliče število okuženih in odšteje 1, temveč naj bo to rekurzivna funkcija, ki kliče sebe in ne drugih funkcij.

Testi