#include #include using namespace std; const int INF = 2e9; struct Edge { // Создаём структуру ребра, которая хранит в себе его концы и вес int a, b, w; }; vector> G; // G - список смежности void dfs(int v, vector &was) { // dfs - Обычный обход в глубину, который посещает все вершины, достижимые из v и помечает их в was was[v] = true; // Указываем, что посетили v-ую вершину for (int nxt : G[v]) { // Итерируемся по вершинам, смежным с v-ой if (!was[nxt]) { // Если мы ещё не были в nxt-ой вершине, то нужно запустить dfs из неё dfs(nxt, was); // Запускаем dfs из nxt-ой вершины } } } void solve() { int n, m; cin >> n >> m; // Считываем кол-во комнат и рёбер G.resize(n); vector ve(m); // Создаём массив рёбер for (int i = 0; i < m; ++i) { // Итерируемся по рёбрам cin >> ve[i].a >> ve[i].b >> ve[i].w; // Считываем концы ребра и его вес // Уменьшаем номера концов ребра на 1, так как нумерация комнат в задаче идёт с 1, а нам было бы удобнее, если бы она шла с 0 ve[i].a--; ve[i].b--; G[ve[i].a].push_back(ve[i].b); // Добавляем в списке смежности к ve[i].a-ой вершине смежную ve[i].b } vector d(n, -INF); // d[i] = x, означает, что максимальный вес рёбер на пути от 0 до i равен x d[0] = 0; // путь от 0-ой вершины до неё состоит из 0-ля рёбер, следовательно их вес равен 0 for (int k = 0; k < n - 1; ++k) { // Перебираем фазу for (Edge edge : ve) { // Перебираем ребро if (d[edge.a] != -INF && d[edge.b] < d[edge.a] + edge.w) { // Если уже есть како-то путь, ведущий в d[edge.a], и вес пути до edge.b увеличится, если пройти по edge, то делаем релаксацию d[edge.b] = min(INF, d[edge.a] + edge.w); // нужно сделать min с INF, так как при наличии положительных циклов суммарный вес пути может очень быстро увеличиваться и перестанет помещаться в какой-либо тип данных } } } vector in_cycle(n, false); // in_cycle[v] = true, означает, что в v-ую вершину можно попасть из положительного цикла // Так как при отсутствии циклов положительного веса, алгоритм Форда-Беллмана находит все оптимальные значения массива d за (k - 1)-у фазу, то на k-ой фазе изменения затронут только вершины, в которые можно попасть из положительного цикла (Потому что при наличие положительных циклов веса путей можно увеличивать до бесконечности) for (Edge edge : ve) { // Перебираем ребро if (d[edge.a] != -INF && d[edge.b] < d[edge.a] + edge.w) { // Если уже есть како-то путь, ведущий в d[edge.a], и вес пути до edge.b увеличится, если пройти по edge, то делаем релаксацию in_cycle[edge.b] = true; // Помечаем, что в v-ую вершину можно попасть из положительного цикла d[edge.b] = min(INF, d[edge.a] + edge.w); // нужно сделать min с INF, так как при наличии положительных циклов суммарный вес пути может очень быстро увеличиваться и перестанет помещаться в какой-либо тип данных } } if (d[n - 1] == -INF) { // Если d[n - 1] = -INF, то не существует пути из 0-ой вершины в (n - 1)-ую cout << ":("; return; } bool have_pos_cycle = false; // have_pos_cycle = true, если мы из 0-ой вершины можем попасть в положительный цикл, выйти из него и дойти до (n - 1)-ой вершины vector was2(n, false); // was2[v] = true, если из 0-ой вершины можно попасть в v-ую dfs(0, was2); // Запускаем dfs из 0-ля, чтобы получить заполненный was2 for (int i = 0; i < n; ++i) { // Перебираем вершину if (!in_cycle[i]) { // Если в вершину нельзя попасть из положительного цикла, то пропускаем её continue; } vector was1(n, false); // was1[v] = true, если из i-ой вершины можно попасть в v-ую dfs(i, was1); // запускаем dfs из i-ой вершины, чтобы определить, какие вершины из неё достижимы if (was2[i] && was1[n - 1]) { // Если можно из 0-ой вершины дойти до i-ой, а потом от i-ой дойти до (n - 1)-ой, то можно бесконечно набирать положительные значения have_pos_cycle = true; // Указываем, что можно найти цикл положительного веса } } if (have_pos_cycle) { // Если есть цикл положительного веса, то, по условию задачи, выводим :) cout << ":)"; } else { // Если цикла нет cout << d[n - 1]; // Выводим максимальный вес пути от 0 до (n - 1) } } int main() { solve(); return 0; }