Пълна графика само с две възможни разходи. Каква е цената на най-краткия път от 0 до N - 1

Даден ви е пълен неориентиран граф с N върха. Всички ръбове освен K имат цена A. Тези K ръбове имат цена B и вие ги познавате (като списък от двойки). Каква е минималната цена от възел 0 до възел N - 1.

2 <= N <= 500k
0 <= K <= 500k
1 <= A, B <= 500k 

Проблемът очевидно е, когато тези K ръбове струват повече от другите и възел 0 и възел N - 1 са свързани с K-ръб.

Dijkstra не работи. Дори съм пробвал нещо много подобно с BFS.

Step1: Let G(0) be the set of "good" adjacent nodes with node 0.
Step2: For each node in G(0):
              compute G(node)
              if G(node) contains N - 1
                  return step

              else
                  add node to some queue
       repeat step2 and increment step

Проблемът е, че това изразходва много време поради факта, че за всеки възел трябва да направите цикъл от 0 до N - 1, за да намерите "добрите" съседни възли.

Някой има ли по-добри идеи? Благодаря ти.

Редактиране: Ето връзка от състезанието на ACM: http://acm.ro/prob/probleme/B.pdf


person fanton    schedule 12.04.2014    source източник
comment
Също проблем, когато A › B и ръбът от 0 до N-1 струва A. Може да успеете да формирате k*B ‹ A път в този случай.   -  person Gassa    schedule 12.04.2014
comment
Да, но това всъщност не е проблем, защото имате само 500K B-ръбове. И можете да си позволите да направите BFS на тези B-ръбове графика. Проблемът е, когато трябва да изследвате допълнителната графика (защото това са евтините ръбове).   -  person fanton    schedule 12.04.2014
comment
Какво искаш да кажеш с Dijkstra не работи? Твърде скъпо ли е или има нещо в проблема, което го кара да се провали?   -  person user2357112 supports Monica    schedule 12.04.2014
comment
Искам да кажа, че Dijktra е твърде скъпо време за този проблем. O(E * logV) означава приблизително 10^15 операции в най-лошия случай. Твърде много.   -  person fanton    schedule 12.04.2014
comment
@FlaviusAnton Този проблем онлайн ли е някъде? Бих искал да го реша   -  person Niklas B.    schedule 12.04.2014
comment
@NiklasB. Не точно. Виждал съм го в училищна задача (не моя, нали?) и привлече вниманието ми. Също така чух слухове, че първоначално е бил използван в състезанието ACM, но не можах да го намеря.   -  person fanton    schedule 13.04.2014
comment
Всъщност е така. Ето връзката, намерих я по някакъв начин: acm.ro/prob/probleme/B. pdf   -  person fanton    schedule 15.04.2014
comment
@FlaviusAnton Благодаря. За моя изненада решението за O(n log n + m * (log m + log n)) сегментно дърво премина без никакви оптимизации. Проблемът може да бъде оценен онлайн на ICPC Live Archive   -  person Niklas B.    schedule 16.04.2014


Отговори (4)


Това е трудоемка работа по случай:

  1. A ‹ B и 0 и N-1 се съединяват с A -> trivial.
  2. B ‹ A и 0 и N-1 се съединяват с B -> trivial.
  3. B ‹ A и 0 и N-1 се съединяват от A -> Do BFS на графика само с K ръбове.
  4. A ‹ B и 0 и N-1 се съединяват от B -> Можете да проверите в O(N) време дали има път с дължина 2*A (опитайте всеки връх в средата).

    За да проверите други дължини на пътя, следният алгоритъм трябва да свърши работа: Нека X(d) е набор от възли, достижими чрез d по-къси ръбове от 0. Можете да намерите X(d), като използвате следния алгоритъм: Вземете всеки връх v с неизвестно разстояние и итеративно проверете ръбовете между v и върховете от X(d-1). Ако сте намерили къс ръб, тогава v е в X(d), в противен случай сте стъпили на дълъг ръб. Тъй като има най-много K дълги ръбове, можете да стъпите върху тях най-много K пъти. Така че трябва да намерите разстоянието на всеки връх за най-много O(N + K) време.

person usamec    schedule 12.04.2014
comment
Това не е съвсем правилно. Имам пример за графика със 120k възли, добрите ръбове струват 1, а лошите ръбове струват 100 000, а най-краткият път има дължина 5, което е по-голямо от 3. - person fanton; 12.04.2014

Предлагам решение на малко по-общ проблем, при който може да имате повече от два типа ръбове и теглата на ръбовете не са ограничени. За вашия сценарий идеята вероятно е малко пресилена, но изпълнението е доста просто, така че може да е добър начин да се справите с проблема.

Можете да използвате сегментно дърво, за да направите Dijkstra по-ефективен. Ще ви трябват операциите

  • задаване на горна граница в диапазон, както е дадено U, L, R; за всички x[i] с L ‹= i ‹= R, задайте x[i] = min(x[i], u)
  • намерете глобален минимум

Горните граници могат да бъдат лениво избутани надолу по дървото, така че и двете могат да бъдат внедрени в O(log n)

Когато отпускате изходящите ръбове, потърсете ръбовете с цена B, сортирайте ги и актуализирайте диапазоните между тях наведнъж.

Времето на изпълнение трябва да бъде O(n log n + m log m), ако сортирате всички ръбове отпред (по изходящ връх).

РЕДАКТИРАНЕ: Бях приет с този подход. Хубавото при него е, че избягва всякакъв вид специална обвивка. Все още има ~80 реда код.

person Niklas B.    schedule 12.04.2014

В случай, когато A ‹ B, бих използвал нещо като BFS, където ще проверявате къде не можете да достигнете, вместо къде можете. Ето псевдокода:

G(k) is the set of nodes reachable by k cheap edges and no less. We start with G(0) = {v0}

while G(k) isn't empty and G(k) doesn't contain vN-1 and k*A < B
  A = array[N] of zeroes
  for every node n in G(k)
    for every expensive edge (n,m)
      A[m]++
  # now we have that A[m] == |G(k)| iff m can't be reached by a cheap edge from any of G(k)
  set G(k+1) to {m; A[m] < |G(k)|} except {n; n is in G(0),...G(k)}
  k++

По този начин избягвате итерация през (много) евтини ръбове и само итерация през сравнително малкото скъпи ръбове.

person voidengine    schedule 12.04.2014

Както правилно отбелязахте, проблемът идва, когато A > B и край от 0 до n-1 има цена A.

В този случай можете просто да изтриете всички ръбове в графиката, които имат цена A. Това е така, защото оптималният маршрут трябва да има само ръбове с цена B.

След това можете да извършите проста BFS, тъй като разходите за всички ръбове са еднакви. Това ще ви осигури оптимална производителност, както е посочено от тази връзка: Намиране на най-краткия път за равно претеглена графика

Освен това можете да спрете своя BFS, когато общата цена надвиши A.

person Abhishek Bansal    schedule 12.04.2014
comment
Разбира се, прав си, но това е тривиално. Говоря точно за обратния случай, когато тези K ръбове (които са по-малко) са по-скъпи. Защото тогава трябва да направите BFS на допълнителната графика, която има много повече ръбове. - person fanton; 12.04.2014
comment
Същият алгоритъм може да се приложи и в обратния случай. Връзката, която посочих, показва, че BFS е най-добрият подход за решаване на този проблем. Не е необходимо да зацикляте от 0 до N-1 всеки път, ако изтриете ненужните ръбове преди BFS. - person Abhishek Bansal; 12.04.2014