Дейкстры не могут быть использованы здесь, потому что нет способа изменить Дейкстры так, чтобы они возвращали самый длинный путь, а не самый короткий. В общем, проблема самый длинный путь на самом деле является NP-полной, как вы и предполагали, и связана с проблемой коммивояжера, как вы предложили.
То, что вы ищете (как вы знаете), это цикл, произведение весов ребер которого больше 1, то есть w 1 * w 2 * w 3 * ...> 1. Мы можем переосмыслить эту проблему, превратив ее в сумму вместо произведения, если взять журналы обеих сторон:
log (w 1 * w 2 * w 3 ...)> log (1)
=> log (w 1 ) + log (w 2 ) + log (w 3 ) ...> 0
И если мы возьмем отрицательный лог ...
=> -log (w 1 ) - log (w 2 ) - log (w 3 ) ... <0 (обратите внимание на неравенство перевернутая) </p>
Итак, мы сейчас просто ищем отрицательный цикл на графике, который можно решить с помощью алгоритма Беллмана-Форда (или, если вам не требуется знать путь, алгоритм Флойд-Варшалла)
Сначала мы преобразуем график:
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
w[i][j] = -log(w[i][j]);
Затем мы выполняем стандарт Беллмана-Форда
double dis[N], pre[N];
for (int i = 0; i < N; ++i)
dis[i] = INF, pre[i] = -1;
dis[source] = 0;
for (int k = 0; k < N; ++k)
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
if (dis[i] + w[i][j] < dis[j])
dis[j] = dis[i] + w[i][j], pre[j] = i;
Теперь мы проверяем наличие отрицательных циклов:
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
if (dis[i] + w[i][j] < dis[j])
// Node j is part of a negative cycle
Затем вы можете использовать массив pre
, чтобы найти отрицательные циклы. Начните с pre[source]
и возвращайтесь.