Mephistopheles_

Транспортная задача (ТПР)

Apr 28th, 2022
1,200
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.23 KB | None | 0 0
  1. import copy
  2.  
  3. import numpy as np
  4.  
  5. B = np.array([100, 140, 100, 60])
  6. S = np.array([
  7.     [5, 4, 3, 2],
  8.     [2, 3, 5, 6],
  9.     [3, 2, 4, 3],
  10.     [4, 1, 2, 4]
  11. ])
  12. A = np.array([120,
  13.               60,
  14.               80,
  15.               140])
  16.  
  17.  
  18. # B = np.array([25,10,20,30,15])
  19. # S = np.array([
  20. #     [5, 3, 4, 6, 4],
  21. #     [3, 4, 10, 5, 7],
  22. #     [4, 6, 9, 3, 4],
  23. # ])
  24. # A = np.array([40,
  25. #               20,
  26. #               40])
  27. #
  28.  
  29. def prt(res):  # вывод массива
  30.     global S
  31.     k = 0
  32.     for i in range(res.shape[0]):
  33.         for j in range(res.shape[1]):
  34.             if res[i][j] > 0:
  35.                 k += S[i][j] * res[i][j]  # стоимость * кол-во
  36.  
  37.     print(res, k)
  38.     print("--------")
  39.     print()
  40.     return res, k
  41.  
  42.  
  43. def sv(b=True):  # северо-западный метод
  44.     global A, B, S
  45.     res = np.zeros_like(S)
  46.     for i in range(A.shape[0]):
  47.         for j in range(B.shape[0]):
  48.             x = min(B[j], A[i])  # минимум между тем, сколько необходимо и тем, сколько имеется
  49.             B[j] -= x  # вычитание взятого
  50.             A[i] -= x  # вычитание взятого
  51.             res[i][j] += x  # сохранение результата
  52.     if b:
  53.         res[res == 0] = -1  # поставить на месте всех не использованных -1
  54.     return prt(res)
  55.  
  56.  
  57. def min_st(A, B, S):  # метод минимальной стоимости
  58.     res = np.zeros_like(S)
  59.     l = []
  60.     for i in range(S.shape[0]):
  61.         for j in range(S.shape[1]):
  62.             l.append((S[i][j], i, j))  # сохранение цены и позиций
  63.  
  64.     l.sort()  # сортировка
  65.  
  66.     for _, i, j in l:
  67.         x = min(B[j], A[i])  # минимум между тем, сколько необходимо и тем, сколько имеется
  68.         B[j] -= x  # вычитание взятого
  69.         A[i] -= x  # вычитание взятого
  70.         res[i][j] += x  # сохранение результата
  71.     return prt(res)
  72.  
  73.  
  74. recs = []  # позиции элементов, образующих многоугольник
  75.  
  76.  
  77. def rec(i, j, f, D, X, x, y, ot=[]):  # метод составление многоугольника
  78.     global recs
  79.     if len(recs) != 0:  # выход, если многоугольник составлен
  80.         return
  81.     if i >= X.shape[0] or i < 0 or j >= X.shape[1] or j < 0 or D[i][j]:  # выход, если
  82.         # многоугольник составлен или выход за границы или уже посетили данную клетку
  83.         return
  84.     if i == x and j == y and len(ot) > 2:  # найден ответ
  85.         recs = ot.copy()
  86.         return
  87.     D[i][j] = True  # отметка клетки
  88.     if f:  # идем по вертикали
  89.         rec(i + 1, j, f, D, X, x, y, ot)
  90.         rec(i - 1, j, f, D, X, x, y, ot)
  91.     else:  # идем по горизонтали
  92.         rec(i, j + 1, f, D, X, x, y, ot)
  93.         rec(i, j - 1, f, D, X, x, y, ot)
  94.     b = False
  95.     if X[i][j] != -1:
  96.         ot.append((i, j))
  97.         b = True
  98.     if b:  # если на клетке стоит число
  99.         if f:  # меняем направление
  100.             rec(i, j + 1, not f, D, X, x, y, ot)
  101.             rec(i, j - 1, not f, D, X, x, y, ot)
  102.         else:  # меняем направление
  103.             rec(i + 1, j, not f, D, X, x, y, ot)
  104.             rec(i - 1, j, not f, D, X, x, y, ot)
  105.         ot.pop()
  106.  
  107.     D[i][j] = 0  # ставим обратно, как непосещенную
  108.  
  109.  
  110. def pt(X, res):  # метод перепросчета решения
  111.     global S, recs
  112.     print(X, int(res))
  113.     print("********")
  114.     recs = []
  115.     u, v = np.zeros(X.shape[0]), np.zeros(X.shape[1])
  116.     u[0] = 0
  117.     l = []
  118.     for i in range(X.shape[0]):
  119.         for j in range(X.shape[1]):
  120.             if X[i][j] >= 0:  # сохранение ненулевых элементов
  121.                 l.append((i, j))
  122.     k1, k2 = {0}, set()  # u, v которые уже найдены
  123.     while len(k1) + len(k2) < X.shape[0] + X.shape[1]:
  124.         for a, b in l:
  125.             if a in k1:
  126.                 v[b] = S[a][b] - u[a]  # вычисление нового вертикального элемента
  127.                 k2.add(b)
  128.             if b in k2:
  129.                 u[a] = S[a][b] - v[b]  # вычисление нового диагонального элемента
  130.                 k1.add(a)
  131.     m = []
  132.     for i in range(X.shape[0]):
  133.         for j in range(X.shape[1]):
  134.             if X[i][j] < 0:
  135.                 m.append((S[i][j] - (u[i] + v[j]), i, j))  # вычисление относительных оценок
  136.     m.sort()  # сортировка относительных оценок
  137.     if m[0][0] > 0:  # ответ найден
  138.         return
  139.     rec(m[0][1] + 1, m[0][2], True, np.zeros_like(X), X, m[0][1], m[0][2])  # составляем многоугольник (по диагонали)
  140.     rec(m[0][1] - 1, m[0][2], True, np.zeros_like(X), X, m[0][1], m[0][2])
  141.     rec(m[0][1], m[0][2] + 1, False, np.zeros_like(X), X, m[0][1], m[0][2])  # составляем многоугольник (по вертикали)
  142.     rec(m[0][1], m[0][2] - 1, False, np.zeros_like(X), X, m[0][1], m[0][2])
  143.     mi = np.min([X[recs[i][0]][recs[i][1]] for i in range(len(recs)) if i % 2 == 0])  # минимум в многоугольнике
  144.     b = True
  145.     for i in range(len(recs)):
  146.         if i % 2 == 0:
  147.             X[recs[i][0]][recs[i][1]] -= mi  # позиция на минусе => вычитание
  148.             if X[recs[i][0]][recs[i][1]] == 0 and b:
  149.                 b = False
  150.                 X[recs[i][0]][recs[i][1]] = -1  # удаление первого 0
  151.         else:
  152.             X[recs[i][0]][recs[i][1]] += mi  # позиция на плюсе => прибавление
  153.     X[m[0][1]][m[0][2]] = mi  # добавление новой вершины
  154.     res += m[0][0] * mi  # пересчитывание результата
  155.     pt(X, res)  # запуск с новой таблицей
  156.  
  157. min_st(copy.deepcopy(A), copy.deepcopy(B), copy.deepcopy(S))
  158. pt(*sv())
  159.  
Advertisement
Add Comment
Please, Sign In to add comment