Qraf 10^4-dək təpəyə və 4 \cdot 10^4-dək tilə malikdir, ona görə də onu qonşuluq siyahısı şəklində saxlayacağıq. Bütün tillərin çəkiləri müsbətdir, deməli, ən qısa məsafələri Dijkstra alqoritmi ilə tapmaq olar.
Məsələnin qraf terminləri ilə ifadəsi. və təpələri arasındakı ən qısa yolun uzunluğunu ilə işarə edək. Əgər server şəhərində yerləşirsə, c_i şəhərindən olan qonaq d(c_i, v) gecikməsini alır. Bütün qonaqların ümumi gecikməsi bərabərdir
qiyməti minimal olan təpəsini tapmaq lazımdır, bərabərlik halında isə — nömrəsi ən kiçik olanı.
Niyə Dijkstranı qonaqların şəhərlərindən işə salırıq. Hər bir namizəd-təpə üçün -dən Dijkstra alqoritmini işə salıb qonaqların şəhərinə olan məsafələri toplamaq olardı. Lakin namizədlərin sayı 10^4-dək ola bilər, bu qədər işə salma çox həddən artıqdır. Qeyd edək ki, qraf istiqamətsizdir, ona görə d(c_i, v) = d(v, c_i). Deməli, qonaq c_i-nin şəhərindən Dijkstranın bir dəfə işə salınması dərhal serverin bütün mümkün yerləşdirilmə yerləri üçün bu qonağın gecikməsini verir. Qonaqların sayı -dən çox olmadığına görə, dəfə işə salmaq kifayətdir.
Cəm necə yığılır. İlkin olaraq sıfırlarla doldurulmuş massivi yaradaq. elementi server təpəsində yerləşdirildikdə qonaqların ümumi gecikməsini saxlayacaq.
Sonra hər bir qonaq üçün növbə ilə:
c_i təpəsindən Dijkstra alqoritmini işə salırıq və dist[1..n] massivini alırıq, burada dist[v] = d(c_i, v). Bu, server şəhərində yerləşdikdə -ci qonağın gecikməsidir.
Bütün v = 1, 2, ..., n təpələrini gəzirik və sum[v] += dist[v] əməliyyatını icra edirik. Beləliklə, -ci qonağın töhfəsini serverin hər bir mümkün yerləşdirilmə yerinin ümumi gecikməsinə əlavə edirik.
Bütün qonaq emal edildikdən sonra hər bir elementi düz toplanan — təpəsinə qədər bütün qonaqların gecikmələrini ehtiva edir, yəni sum[v] = S(v).
Cavabın seçilməsi. v = 1, 2, ..., n təpələrini nömrələrin artma qaydasında gəzirik və minimal cəmə malik təpəni yadda saxlayırıq. Cavabı yalnız sərt bərabərsizlik sum[v] < best olduqda yeniləyirik. Bu zaman eyni minimal cəmə malik bir neçə təpə olduqda onlardan birincisi, yəni ən kiçik nömrəli olan qalır.
Minimum yalnız qonaqların şəhərləri arasında deyil, bütün təpə arasında axtarılır: optimal yer qonağı olmayan şəhər ola bilər.
Misal
Misalda verilmiş qraf aşağıdakı şəkildədir:
Qonaqların yaşadığı təpələrdən — və — Dijkstra alqoritmini işə salaq. Bu təpələrin hər biri üçün bütün digər şəhərlərə qədər ən qısa məsafələri müəyyən edək.
Sonra qrafın hər bir təpəsi üçün qonaqları olan bütün şəhərlərə qədər olan məsafələrin cəmini tapaq. Məsafələrin minimal cəmi -ə bərabərdir və o, ən kiçik nömrəli təpədə əldə edilir.
Beləliklə, server nömrəli şəhərdə yerləşdirilməlidir. Ondan qonaqların yaşadığı şəhərlərə qədər ümumi məsafə 5 + 0 + 8 = 13 təşkil edir.
Alqoritmin reallaşdırılması
Sonsuzluq sabitini elan edək.
#define INF 0x3F3F3F3Fstrukturu til haqqında məlumatı saxlayacaq: tilin apardığı təpəsini və bu tilin çəkisini.
struct edge
{
int node, dist;
edge(int node, int dist) : node(node), dist(dist) {}
};(node, dist) cütlərini qiymətinin azalması üzrə sıralamaq üçün komparator elan edək.
bool operator< (edge a, edge b)
{
return a.dist > b.dist;
}Qrafı təqdim etmək üçün qonşuluq siyahısı elan edək.
vector<vector<edge> > g;Dijkstra funksiyası Dijkstra alqoritmini reallaşdırır. O, giriş olaraq qrafını və başlanğıc təpəsini qəbul edir. Qaytarılan qiymət massividir, burada təpəsindən təpəsinə qədər ən qısa məsafəni saxlayır.
void Dijkstra(vector<vector<edge> >& g, vector<int>& d, int start)
{
priority_queue<edge> pq;
pq.push(edge(start, 0));
d = vector<int>(n + 1, INF);
d[start] = 0;
while (!pq.empty())
{
edge e = pq.top(); pq.pop();
int v = e.node;
if (e.dist > d[v]) continue;
for (auto e : g[v])
{
int to = e.node;
int cost = e.dist;
if (d[v] + cost < d[to])
{
d[to] = d[v] + cost;
pq.push(edge(to, d[to]));
}
}
}
}Proqramın əsas hissəsi. Giriş məlumatlarını oxuyuruq.
scanf("%d %d %d", &n, &m, &k);
c.resize(k);
for (i = 0; i < k; i++)
scanf("%d", &c[i]);Giriş çəkili qrafını oxuyuruq.
g.resize(n + 1);
for (i = 0; i < m; i++)
{
scanf("%d %d %d", &a, &b, &w);
g[a].push_back(edge(b, w));
g[b].push_back(edge(a, w));
}Qonaqların yaşadığı şəhərlərdən Dijkstra alqoritmini işə salırıq.
dp.resize(n + 1);
for (i = 0; i < k; i++)
{
Dijkstra(g, dist, c[i]);
for (j = 1; j <= n; j++)
dp[j] += dist[j];
}Bu anda təpəsindən qonaqların yerləşdiyi bütün şəhərlərə qədər ən qısa məsafələrin cəmini saxlayır. massivinin elementləri arasında minimal qiyməti tapmaq və müvafiq cavabı çıxarmaq qalır. dəyişəni serverin yerləşdirilməli olduğu ən kiçik nömrəli təpəni saxlayır.
res = INF;
for (i = 1; i <= n; i++)
{
if (dp[i] < res)
{
res = dp[i];
ptr = i;
}
}Cavabı çıxarırıq.
printf("%d %d\n", ptr, dp[ptr]);