Побудуємо граф у вигляді списку суміжності , де містить пари чисел такі, що з предметів та можна сконструювати предмет : (i, j) \to a.
Нехай — масив, спочатку такий, що містить вартість покупки предметів (cost[i] = c_i). В кінці роботи алгоритму міститиме мінімальну кількість грошей, необхідну для отримання предмета .
Спочатку всі предмети вважаються необробленими (used[i] = 0).
Поки існує принаймні один необроблений предмет:
Знаходимо предмет з найменшою вартістю;
Застосовуємо всі правила, перелічені в ;
Позначаємо предмет як оброблений: used[a] = 0;
Для кожного правила (a, b) \to to з перераховуємо
Приклад
Розглянемо перший тест. Є предметів з такими вартістями їх покупки:
Є три правила конструювання предметів. Побудуємо на їх основі список суміжності.
Предмет має найменшу вартість cost[2] = 0. Застосовуємо всі правила, в яких бере участь предмет , а саме ті, що перелічені в . Після цього позначаємо предмет як оброблений.
Наступним необробленим предметом з найменшою вартістю буде . Застосовуємо правила, перелічені в . Вартість предметів при цьому не змінюється.
Далі необробленим предметом з найменшою вартістю стає предмет . Застосовуємо правило з .
У подальших операціях вартість предметів не змінюється. Таким чином, мінімальна вартість отримання предмета дорівнює .
Реалізація алгоритму
Оголосимо робочі масиви. Оголосимо список суміжності , який міститиме правила конструювання предметів.
vector<int> cost, used;
vector<vector<pair<int, int>>> g;Читаємо вхідні дані. Ініціалізуємо масиви.
scanf("%d %d", &n, &m);
g.resize(n + 1);
cost.resize(n + 1);
used.resize(n + 1);Читаємо вартості покупки предметів.
for (i = 1; i <= n; i++)
scanf("%d", &cost[i]);Читаємо правила конструювання предметів і на їх основі будуємо список суміжності.
for (i = 0; i < m; i++)
{
scanf("%d %d %d", &a, &x, &y);
g[x].push_back(make_pair(y, a));
g[y].push_back(make_pair(x, a));
}Здійснюємо ітерацій.
for (k = 0; k < n; k++)
{Серед необроблених предметів шукаємо той, у якого найменша вартість. Нехай це буде предмет з номером .
mn = 2e9; a = -1;
for (i = 1; i <= n; i++)
if (!used[i] && cost[i] < mn)
{
mn = cost[i];
a = i;
}Позначаємо предмет як оброблений.
used[a] = 1;Перебираємо всі правила, в яких бере участь предмет .
for (auto x : g[a])
{
b = x.first;
to = x.second; // (a, b) -> to
if (cost[a] + cost[b] < cost[to]) cost[to] = cost[a] + cost[b];
}
}Виводимо мінімальну кількість грошей, необхідну для покупки першого предмета.
printf("%d\n", cost[1]);Python реалізація
У Python — це спеціальне значення, що позначає нескінченність. Воно доступне в модулі і для використання модуль необхідно імпортувати.
from math import infЧитаємо вхідні дані.
n, m = map(int, input().split())
cost = [0] + list(map(int, input().split()))Ініціалізуємо списки.
used = [False] * (n + 1)
g = [[] for _ in range(n + 1)]Читаємо правила конструювання предметів і на їх основі будуємо список суміжності.
for _ in range(m):
a, x, y = map(int, input().split())
g[x].append((y, a))
g[y].append((x, a))Виконуємо ітерацій.
for k in range(n):На кожній ітерації серед необроблених предметів шукаємо той, у якого найменша вартість. Нехай це буде предмет з номером .
mn = inf
a = -1
for i in range(1, n + 1):
if not used[i] and cost[i] < mn:
mn = cost[i]
a = iПозначаємо предмет як оброблений.
used[a] = TrueПеребираємо всі правила, в яких бере участь предмет .
for b, to in g[a]:
if cost[a] + cost[b] < cost[to]:
cost[to] = cost[a] + cost[b]Виводимо мінімальну кількість грошей, необхідну для покупки першого предмета.
print(cost[1])