68. Metro

 

The metro system consists of n stations located on l lines. Each station belongs to one or several lines (in this case, a passenger can transfer to any of the lines passing through this station). Each line includes at least two stations and intersects with at least one other line. The metro network is connected.

Travel between two adjacent stations on the same line is possible in both directions and takes 2 minutes. A transfer from one line to another within the same station takes 1 minute. Other time costs can be neglected.

Determine the minimum time required for the manager of the company “Diez-Product” to travel from station a to the company’s office located near station b.

 

Input. The first line contains two positive integers n and l (1 ≤ l ≤ 10). Each of the next l lines lists the consecutive station numbers of each metro line. The last line contains the numbers and line indices of the starting and destination stations. All numbers are positive and do not exceed  70.

 

Output. Print the minimum travel time between the specified stations.

 

Sample input

Sample output

7 3

2 1 3

6 1 4 5

5 7

2 1 7 3

10

 

 

SOLUTION

graphsDijkstra

 

Анализ алгоритма

Кратчайшее расстояние от источника до вершины v, принадлежащей линии l, храним в dist[v][l], где 1 v 70, 1 l 10. Граф храним в виде списков смежности. Вместе с направлением и стоимостью ребра храним номер линии метро, которой принадежит вершина куда направлено ребро.

Стартуем со станции s, находящейся на линии line1. Ответ на задачу – минимальная стоимость, за которую можно добраться до вершины f на линии line2. При движении между вершинами следует совершить проверку: если вершины принадлежат разным линиям, то следует добавить 1 (совершить пересадку).

При помощи алгоритма Дейкстры находим кратчайшее расстояния из сосотяния (s, line1) в (f, line2).

 

Example

In the given example, it is required to find the shortest route from station 2 on line 1 to station 7 on line 3.

·        Move along line 1 from station 2 to station 1: 2 minutes.

·        Transfer at station 1 from line 1 to line 21 minute.

·        Move along line 2 from station 1 to station 5: 4 minutes.

·        Transfer at station 5 from line 2 to line 3: 1 minute.

·        Move along line 3 from station 5 to station 7: 2 minutes.

Thus, the entire trip takes 10 minutes.

 

Реализация алгоритма

Количество вершин в графе не более MAX = 71. Количество линий не более LINES = 11.

 

#define MAX 71

#define LINES 11

 

Кратчайшее расстояние от источника до вершины v, принадлежащей линии l, храним в dist[v][l]. Объявим массив кратчайших расстояний.

 

int dist[MAX][LINES];

 

Структура node содержит информацию о ребре:

·        to – направление ребра;

·        costстоимость ребра;

·        lineкакой линии метро ребро принадлежит;

 

struct node

{

  int to, cost, line;

  node(int to, int cost, int line) : to(to), cost(cost), line(line) {}

};

 

Структура node также будет использоваться в очереди с приоритетами, где

·        to – текущая вершина;

·        costминимальная стоимость проезда до вершины to (на линии line);

·        lineномер линии метро, на которой находится вершина to;

 

В очереди с приоритетами вершины сортируются по возрастанию стоимости проезда.

 

bool operator< (node a, node b)

{

  return a.cost > b.cost;

}

 

Список смежности вершин графа.

 

vector<vector<node> > g;

 

Основная часть программы. Читаем входные данные.

 

scanf("%d %d", &n, &l);

 

g.resize(n + 1);

 

Читаем i-ую линию метро. Время движения между соседними станциями u и v равно 2.

 

for (i = 1; i <= l; i++)

{

 

Читаем станцию u – первую станцию i-ой линии метро. За станцией u идет станция v.

 

  scanf("%d ", &u);

  while (scanf("%d%c", &v, &ch))

  {

 

Движение возможно в обоих направлениях. Стоимость ребра равна 2.

 

    g[u].push_back(node(v, 2, i));

    g[v].push_back(node(u, 2, i));

    u = v;

 

Как только доходим до конца строки – заканчиваем читать данные очередной линии метро.

 

    if (ch == '\n') break;

  }

}

 

Инициализируем массив кратчайших расстояний.

 

  for (i = 1; i <= n; i++)

  for (j = 1; j <= l; j++)

    dist[i][j] = 2000000000;

 

Читаем информацию о начальной и конечной станции. Для каждой станции задается линия, которой она принадлежит.

 

  scanf("%d %d %d %d", &s, &line1, &f, &line2);

 

Стартуем со станции s, находящейся на линии line1.

 

  dist[s][line1] = 0;

 

priority_queue<node, vector<node> > pq;

 

Заносим в очередь структуру node, содержащую начальную вершину s на линии line1. Стоимость попадания в начальную вершину равна 0.

 

pq.push(node(s, 0, line1)); // (v, cost, line)

while (!pq.empty())

{

 

Извлекаем из очереди вершину v с наименьшей стоимостью.

 

  int cost = pq.top().cost;

  int v = pq.top().to;

  int l1 = pq.top().line;

  pq.pop(); // dist[v][l1] = cost

 

Перебираем вершины, связанные с v.

 

  for (i = 0; i < g[v].size(); i++)

  {

 

Имеется ребро vto стоимостью w, принадлежащее линии l2.

 

    int to = g[v][i].to;

    int w = g[v][i].cost;

    int l2 = g[v][i].line;

 

Если двигаться в to по ребру vto, то стоимость составит cost + w.

 

    int tot_cost = cost + w;

 

Если линии у вершин v и to разные, то следует совершить пересадку с линии l1 на линию l2.

 

    if (l1 != l2) tot_cost += 1;

 

Если движение по ребру vto дает лучший результат, то улучшаем значение dist[to][l2] и заносим вершину to в очередь (стоимость попадания в нее составляет tot_cost и она находится на линии l2).

 

    if (tot_cost < dist[to][l2])

    {

      dist[to][l2] = tot_cost;

      pq.push(node(to, tot_cost, l2));

    }

  }

}

 

Вывод ответа – стоимости добраться до вершины f на линии line2.

 

printf("%d\n", dist[f][line2]);