Advertisement
Guest User

Untitled

a guest
Jun 26th, 2019
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.73 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3.  
  4. using namespace std;
  5.  
  6.  
  7. const int MAXN = 18; // максимальная размерность нашей задачи
  8. const int INF = 1000000000; // импровизированная бесконечность
  9.  
  10. // колличество вершин
  11. int n;
  12. // матрица смежности исходного графа
  13. int graph[MAXN][MAXN];
  14.  
  15. /*
  16.  * в dp[mask][v] -- длинна кратчайшего
  17.  * гамельтонова пути, который содержит все вершины mask,
  18.  * и заканчивается в вершине v
  19.  *
  20.  * mask -- целове число
  21.  * если j-ый бит числа mask равен единице,
  22.  * то подразумевается, что гамильтонов путь содержит
  23.  * вершину j
  24.  */
  25. int dp[(1 << MAXN)][MAXN];
  26.  
  27. // наш ответ -- искомый путь
  28. int ans[MAXN];
  29.  
  30. // наш текущая лучшая длинна пути, и вершина, в которой этот путь заканчивается
  31. // в конце программы тут будет лежать итоговая стоимость пути и вершина, в которой этот путь заканчивается
  32. int cost = INF, bestv;
  33.  
  34. int main() {
  35.     freopen("trader.in", "r", stdin);
  36.     freopen("trader.out", "w", stdout);
  37.  
  38. /*
  39.  * Эта задача о поиске кратчайшего пути в графе,
  40.  * который содержит все вершины
  41.  * Такой путь называется гамельтоновым
  42.  *
  43.  * Это задача коммивояжера о нахождении
  44.  * кратчайшего гамельтоного цикла в ориентированном графе,
  45.  * модифицированная для поиска гамельтонова пути
  46.  */
  47.  
  48.     // считываем входные данные
  49.     cin >> n;
  50.     for (int i = 0; i < n; i++) {
  51.         for (int j = 0; j < n; j++) {
  52.             cin >> graph[i][j];
  53.         }
  54.     }
  55.  
  56.     // заполняем массив dp бесконечностями
  57.     for (int mask = 1; mask < (1<<n); mask++) {
  58.         for (int i = 0; i < n; i++) {
  59.             dp[mask][i] = INF;
  60.         }
  61.     }
  62.  
  63.     /*
  64.      * создаем базу нашей динамики
  65.      * длинна пути, который содержит только первую вершину,
  66.      * и заканчивается в ней же, равна нулю
  67.     */
  68.     dp[1][0] = 0;
  69.    
  70.     /*
  71.      * 1 << a -- побитовый сдвиг на a позиций влево
  72.      * равносилен умножению на 2^a
  73.     */
  74.  
  75.     //перебираем все возможные множества вершин
  76.     for (int mask = 0; mask < (1<<n); mask++) {
  77.         // перебираем конец пути
  78.         for (int i = 0; i < n; i++) {
  79.             // перебираем вершину, из которой мы могли придти в вершину i
  80.             for (int j = 0; j < n; j++) {
  81.                 // если вершины i и j есть в множестве mask и есть ребро между ними
  82.                 if (mask & (1<<j) && mask & (1<<i) && graph[j][i] > 0) {
  83.                     // обновняем ответ для dp[mask][i]
  84.                     dp[mask][i] = min(dp[mask][i], dp[mask - (1<<i)][j] + graph[j][i]);
  85.                 }
  86.             }
  87.         }
  88.     }
  89.  
  90.     // ищем ответ -- путь завершился в одной из вершин 0 .. N - 1, и учавствуют все вершины
  91.     for (int i = 0; i < n; i++) {
  92.         if (cost > dp[(1<<n) - 1][i]) {
  93.             cost  = dp[(1<<n) - 1][i];
  94.             bestv = i;
  95.         }
  96.     }
  97.  
  98.     if (cost != INF) {
  99.         // если ответ есть
  100.         // восстанавливаем сам цикл
  101.  
  102.         // наша текущая вершина -- изначально мы в последней вершине
  103.         int curv = bestv;
  104.         // изначально рассматриваем множество всех вершин
  105.         int mask = (1<<n) - 1;
  106.  
  107.         // добавляем текущую вершину в ответ
  108.         ans[n - 1] = curv;
  109.         /* cnt -- колличество вершин в пути в данный момент + 1
  110.          * cnt -- итератор на текущее пустое место в массиве ответа
  111.          * для записи следующей вершины
  112.         */
  113.         int cnt = 2;
  114.  
  115.         // пока в множестве есть вершины
  116.         while (mask != 1) {
  117.             // перебираем вторую вершину
  118.             for (int i = 0; i < n; i++) {
  119.                 // если обе вершины в множестве и существует ребро и ..
  120.                 if ((mask & (1<<i)) != 0 && curv != i && graph[i][curv] > 0 &&
  121.                     dp[mask][curv] == dp[mask - (1<<curv)][i] + graph[i][curv]) {
  122.                     // делаем "шаг назад" -- обновляем mask и curv
  123.                     mask -= (1<<curv);
  124.                     curv = i;
  125.                     // добавляем в ответ вершину curv
  126.                     ans[n - cnt] = curv;
  127.                     cnt++;
  128.                 }
  129.             }
  130.         }
  131.  
  132.         // выводим путь
  133.         cout << cost << "\n";
  134.         for (int i = 0; i < n; i++) {
  135.             cout << ans[i] + 1 << " ";
  136.         }
  137.     } else {
  138.         // иначе -- если не существует гамельтонова пути
  139.         cout << -1;
  140.     }
  141.     return 0;
  142. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement