Разбор
Отсортируем дороги (ребра графа) по возрастанию их опасности. Для решения задачи будем использовать систему непересекающихся множеств. Изначально образуем множеств, каждое из которых содержит одну вершину. Просматриваем ребра в порядке возрастания опасности. Для каждого ребра объединяем множества, содержащие вершины и . Как только вершины и попадут в одно множество, алгоритм завершается. В этом случае путь от первой вершины до -ой уже будет существовать, причем опасности дорог, через которые проходит этот путь, будут не большими чем опасность последней рассмотренной дороги.
Таким образом если после рассмотрения ребра представители вершин и совпадут, то опасность самого безопасного маршрута будет равна опасности дороги .
Пример
В первом тесте опасность самого безопасного маршрута равна .
Рассмотрим второй тест.
Ребра обрабатываются в порядке возрастания их опасности. Как только будет обработано ребро с опасностью , вершины и соединятся и алгоритм останавливается.
Реализация алгоритма
Объявим массив , используемый системой непересекающихся множеств. В массиве будем хранить ребера графа.
#define MAX 1000001 int mas[MAX]; struct Edge { int x, y, danger; } e[MAX];
Функция Repr находит представителя множества, в котором находится вершина . При этом для избежания вердикта Time Limit используется эвристика: если представителем вершины является , то следует положить .
int Repr(int n) { if (n == mas[n]) return n; return mas[n] = Repr(mas[n]); }
Функция Union объединяет множества, содержащие вершины и .
int Union(int x,int y) { int x1 = Repr(x),y1 = Repr(y); mas[x1] = y1; return (x1 != y1); }
Объявим компаратор lt для сравнения ребер. Дороги сортируются по возрастанию их опасности.
int lt(Edge a, Edge b) { return (a.danger < b.danger); }
Основная часть программы. Читаем количество городов и дорог .
scanf("%d %d",&n,&m);
Инициализируем массив .
for(i = 1; i <= n; i++) mas[i] = i;
Читаем ребра графа в массив .
for(i = 0; i < m; i++) scanf("%d %d %d",&e[i].x,&e[i].y,&e[i].danger);
Сортируем ребра по возрастанию опасности.
sort(e,e+m,lt);
Переберем ребра, начиная с наименее опасного. Объединяем множества, содержащие их вершины. Как только вершины и попадут в одно множество ( станет равным ), самый безопасный путь будет найден. Его опасность будет равна опасности последнего обрабатываемого ребра, то есть .
for(i = 0; i < m; i++) { Union(e[i].x,e[i].y); if (Repr(1) == Repr(n)) break; }
Выводим результат.
printf("%d\n",e[i].danger);
Java реализация
import java.util.*; class Edge { int x, y, danger; Edge (int x, int y, int danger) { this.x = x; this.y = y; this.danger = danger; } }; public class Main { static int mas[], size[]; static int Repr(int n) { if (n == mas[n]) return n; return mas[n] = Repr(mas[n]); } static boolean Union(int x,int y) { x = Repr(x); y = Repr(y); if(x == y) return false; if (size[x] < size[y]) { int temp = x; x = y; y = temp; } mas[y] = x; size[x] += size[y]; return true; } public static class MyFun implements Comparator<Edge> { public int compare(Edge a, Edge b) { return a.danger - b.danger; } } public static void main(String[] args) { Scanner con = new Scanner(System.in); int n = con.nextInt(); int m = con.nextInt(); mas = new int[n+1]; size = new int[n+1]; for(int i = 1; i <= n; i++) { mas[i] = i; size[i] = 1; } Vector<Edge> v = new Vector<Edge>(); for(int i = 0; i < m; i++) { int x = con.nextInt(); int y = con.nextInt(); int dust = con.nextInt(); v.add(new Edge(x,y,dist)); } Collections.sort(v, new MyFun()); int index = 0; for(int i = 0; i < m; i++) { Union(v.get(i).x,v.get(i).y); if (Repr(1) == Repr(n)) { index = i; break; } } System.out.println(v.get(index).danger); con.close(); } }
Python реализация
Объявим структуру ребро .
class Edge: def __init__(self, x, y, danger): self.x = x self.y = y self.danger = danger
Функция Repr находит представителя множества, в котором находится вершина . При этом для избежания вердикта Time Limit используется эвристика: если представителем вершины является , то следует положить .
def Repr(n): if n == mas[n]: return n mas[n] = Repr(mas[n]) return mas[n]
Функция Union объединяет множества, содержащие вершины и .
def Union(x, y): x1 = Repr(x) y1 = Repr(y) mas[x1] = y1 return x1 != y1
Основная часть программы. Читаем количество городов и дорог .
n, m = map(int, input().split())
Инициализируем список , используемый системой непересекающихся множеств.
mas = [i for i in range(n + 1)]
Читаем ребра графа в список .
e = [] for i in range(m): x, y, danger = map(int, input().split()) e.append(Edge(x, y, danger))
Сортируем ребра по возрастанию опасности.
e.sort(key=lambda x: x.danger)
Переберем ребра, начиная с наименее опасного. Объединяем множества, содержащие их вершины. Как только вершины и попадут в одно множество ( станет равным ), самый безопасный путь будет найден. Его опасность будет равна опасности последнего обрабатываемого ребра, то есть .
for i in range(m): Union(e[i].x, e[i].y) if Repr(1) == Repr(n): break
Выводим результат.
print(e[i].danger)