Məsələnin şərtinə əsasən, bir adadan çıxdıqdan sonra siz bir daha oraya qayıda bilməzsiniz. Deməli, təpələri adalar, kənarları isə körpülər olan qraf yönlü asiklik qrafdır. Siz yalnız çıxış körpüsü olmayan adasında, yəni çıxış dərəcəsi sıfır olan dalan təpədə ilişib qala bilərsiniz: OutDegree[v] = 0.
prob[v] ilə gəzinti zamanı təpəsinə çatma ehtimalını işarə edək. Başlanğıc təpə üçün prob[r] = 1; bütün digər təpələr üçün ilkin olaraq prob[v] = 0. Qrafda dövrələr olmadığından, hər təpəyə ən çoxu bir dəfə baş çəkmək olar.
Tutaq ki, təpəsindən OutDegree[u] kənar çıxır. -da olarkən biz onlardan birini bərabər ehtimalla seçirik, deməli u \to v kənarı ilə prob[u] / OutDegree[u] ehtimalla hərəkət edirik. təpəsinə yalnız onun birbaşa sələflərindən çatmaq olar. Buna görə prob[v] -yə daxil olan bütün u \to v kənarlarının töhfələrinin cəminə bərabərdir:
prob[v] qiyməti yalnız onun bütün sələflərinin ehtimalları yekunlaşdıqdan sonra hesablana bilər. Bu məhz topoloji sıralama ilə verilən emal ardıcıllığıdır: hər təpə, ondan kənar çıxan bütün təpələrdən sonra görünür. Buna görə biz topoloji sıranı Kahn alqoritmi ilə qururuq və eyni zamanda ehtimalları kənarlar boyunca "itələyirik".
Alqoritm belədir:
hər təpəsi üçün onun giriş dərəcəsini InDegree[v] və çıxış dərəcəsini OutDegree[v] hesablayın;
giriş dərəcəsi sıfır olan bütün təpələri növbəyə əlavə edin və prob[r] = 1 təyin edin;
növbə boş olmayana qədər ondan təpəsini çıxarın. Bu ana qədər onun bütün sələfləri artıq emal olunub, ona görə prob[v] qiyməti yekundur. Hər v \to to kənarı üçün prob[v] / OutDegree[v] qiymətini prob[to]-ya əlavə edin və InDegree[to]-nu azaldın. Əgər təpəsinin giriş dərəcəsi sıfır olarsa, onu növbəyə əlavə edin.
Başlanğıcda növbədə təkcə başlanğıc təpə deyil, giriş dərəcəsi sıfır olan bütün təpələr var. -dən çatıla bilməyən təpələr də emal olunur, lakin onların ehtimalı sıfır olaraq qalır və cavaba təsir etmir.
Cavabın tapılması. Dalan təpələr arasından maksimum ehtimalını tapın. Sonra artan sıra ilə |prob[v] - mx| \le 10^{-9} şərtini ödəyən bütün dalan təpələrinin indekslərini çap edin. Dözümlülüklə müqayisə etmək lazımdır, çünki ehtimallar yuvarlaqlaşdırma xətaları ilə üzən nöqtəli ədədlərdə hesablanır.
Mürəkkəblik. Hər təpə növbəyə dəqiq bir dəfə əlavə olunur və ondan çıxarılır, hər kənar isə bir dəfə baxılır. Alqoritmin işləmə vaxtı O(n + m)-dir.
Misal
Misaldakı qraf üzərində alqoritmi simulyasiya edək. Hər təpənin yanında ona çatma ehtimalı prob[v] göstərilib. Emal olunmuş təpələr boz rənglə, cari addımda ehtimalın paylandığı kənarlar mavi rənglə, artıq baxılmış kənarlar isə kəsik xətlə göstərilib.
Başlanğıcda (sol şəkil) prob[1] = 1, digər bütün təpələrin ehtimalı isə -dır. Təpə giriş dərəcəsi sıfır olan yeganə təpə olduğundan, növbədən ilk çıxarılan o olur.
təpəsindən dörd kənar çıxır, ona görə prob[1] = 1 ehtimalı və təpələri arasında bərabər bölünür: hər biri 1 / 4 = 0.25 alır (sağ şəkil). təpəsindən çıxan kənarları çıxardıqdan sonra və təpələrinin giriş dərəcəsi sıfır olur və onlar növbəyə əlavə olunur.
Sonra təpəsi emal olunur. Ondan iki kənar çıxır, ona görə prob[2] / 2 = 0.25 / 2 = 0.125 qiyməti və -ə əlavə olunur. Nəticədə prob[4] = prob[5] = 0.375 alırıq (aşağı sol şəkil). təpəsinin giriş dərəcəsi sıfır olur və o növbəyə əlavə olunur.
Sonra təpəsi emal olunur. Ondan yalnız bir 3 \to 4 kənarı çıxır, ona görə qiyməti prob[3] / 1 = 0.25 qədər artır və olur (aşağı sağ şəkil). İndi təpəsi də növbəyə əlavə olunur.
və təpələrindən çıxan kənar olmadığından, onların emalı heç bir ehtimalı dəyişmir. Nəticədə alınan topoloji sıra 1, 2, 3, 5, 4-dür.
Dalan təpələr və -dir, ehtimalları isə uyğun olaraq və -dir. Onların cəmi -ə bərabərdir: biz hardasa mütləq ilişib qalacağıq. Maksimum ehtimal yalnız təpəsində əldə olunur, bu da cavabdır.
Alqoritmin tətbiqi
sabitini elan edin — üzən nöqtəli ədədləri müqayisə etmək üçün dözümlülük.
#define EPS 1e-9Giriş qrafını qonşuluq siyahısı kimi saxlayın. Təpələrin giriş və çıxış dərəcələrini InDegree və OutDegree massivlərində saxlayın. növbəsi Kahn alqoritmində istifadə olunur. prob[v]-də təpəsinə çatma ehtimalını hesablayırıq.
vector\u003cvector\u003cint\u003e\u003e g;
vector\u003cint\u003e InDegree, OutDegree;
deque\u003cint\u003e q;
vector\u003cdouble\u003e prob;Adaların sayı , körpülərin sayı və başlanğıc adanın indeksi -i oxuyun. Qonşuluq siyahısını və dərəcə massivlərini işə salın.
scanf("%d %d %d", \u0026n, \u0026m, \u0026r);
g.assign(n + 1, vector\u003cint\u003e());
InDegree.assign(n + 1, 0);
OutDegree.assign(n + 1, 0);Körpüləri oxuyun və qrafı qurun. Hər a \to b kənarı üçün təpəsinin çıxış dərəcəsini və təpəsinin giriş dərəcəsini artırın.
for (i = 0; i \u003c m; i++)
{
scanf("%d %d", \u0026a, \u0026b);
g[a].push_back(b);
OutDegree[a]++;
InDegree[b]++;
}Giriş dərəcəsi sıfır olan bütün təpələri növbəyə əlavə edin — topoloji sıralama onlardan başlayır.
for (i = 1; i \u003c InDegree.size(); i++)
if (InDegree[i] == 0) q.push_back(i);Başlanğıc təpəsində olma ehtimalı -dir. Bütün digər təpələr üçün ilkin ehtimal -dır: funksiyası massivini sıfırlarla doldurur.
prob.resize(n + 1);
prob[r] = 1;Kahn alqoritmini işə salın. Təpələr növbədən topoloji sırayla çıxarılır.
while (!q.empty())
{Növbədən təpəsini çıxarın. Bu ana qədər onun bütün sələfləri artıq emal olunub, ona görə prob[v] qiyməti yekundur. (v, to) kənarları üzərində iterasiya edin. təpəsindən OutDegree[v] kənar çıxır, hər biri bərabər ehtimalla seçilir. Buna görə v \to to kənarı ilə prob[v] / OutDegree[v] ehtimalla hərəkət edirik. Bu qiyməti prob[to]-ya əlavə edin.
v = q.front(); q.pop_front();
for (int to : g[v])
{
prob[to] += prob[v] / OutDegree[v];(v, to) kənarını qrafdan silin — təpəsinin giriş dərəcəsini azaldın.
InDegree[to]--;Əgər təpəsinin giriş dərəcəsi sıfır olarsa, onun bütün sələfləri emal olunub və prob[to] qiyməti yekundur. -nu növbəyə əlavə edin.
if (InDegree[to] == 0) q.push_back(to);
}
}Dalan təpələr — çıxış körpüsü olmayan (OutDegree[i] = 0) adalar — arasında maksimum ehtimalını tapın.
mx = 0;
for (i = 1; i \u003c= n; i++)
if (OutDegree[i] == 0 \u0026\u0026 prob[i] \u003e mx) mx = max(mx, prob[i]);Ehtimalı -dən ən çoxu qədər fərqlənən bütün dalan təpələrin indekslərini artan sıra ilə çap edin. Belə təpələrdən bir neçəsi ola bilər.
for (i = 1; i \u003c= n; i++)
if (OutDegree[i] == 0 \u0026\u0026 fabs(prob[i] - mx) \u003c= EPS)
printf("%d ", i);