gmo61520

Untitled

Mar 12th, 2016
184
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.89 KB | None | 0 0
  1. from queue import *
  2.  
  3. # строим граф из входных данных
  4. def solve_graph(input_list):
  5. vertices_number = input_list[0][0]
  6. root_id = input_list[0][1]
  7. edges_number = vertices_number - 1
  8.  
  9. vertices = []
  10. for i in range(0, vertices_number):
  11. vertices.append({ 'id': i, 'left': None, 'right': None })
  12.  
  13. root_vertice = vertices[root_id]
  14.  
  15. # создаём таблицу «ID вершины → список соседей»
  16. # для больших деревьев с ней где-то в ≈310 раз быстрее
  17. edges = {}
  18. for i in range(1, edges_number + 1):
  19. entry = input_list[i]
  20.  
  21. if entry[0] in edges:
  22. edges[entry[0]].append(entry[1])
  23. else:
  24. edges[entry[0]] = [ entry[1] ]
  25.  
  26. if entry[1] in edges:
  27. edges[entry[1]].append(entry[0])
  28. else:
  29. edges[entry[1]] = [ entry[0] ]
  30.  
  31. arrange_children_wrapper = None
  32.  
  33. # распихаем потомков по слотам
  34. def arrange_children(vertice, vertice_parent_id):
  35. vertice_id = vertice['id']
  36.  
  37. # добавляем потомка в незанятый слот
  38. def add_child(child):
  39. if vertice['left'] == None:
  40. vertice['left'] = child
  41. else:
  42. vertice['right'] = child
  43.  
  44. # быстренько выдёргиваем соседей из той таблицы
  45. if vertice_id in edges:
  46. for i in edges[vertice_id]:
  47. if i != vertice_parent_id:
  48. add_child(vertices[i])
  49.  
  50. # без рекурсии
  51. queue = Queue()
  52.  
  53. current_vertice = root_vertice
  54. current_parent_id = -1
  55.  
  56. while True:
  57. arrange_children(current_vertice, current_parent_id)
  58.  
  59. left = current_vertice['left']
  60. right = current_vertice['right']
  61. current_parent_id = current_vertice['id']
  62.  
  63. if left != None:
  64. current_vertice = left
  65. if right != None:
  66. queue.put(( right, current_parent_id ))
  67. elif right != None:
  68. current_vertice = right
  69. elif not queue.empty():
  70. current_vertice, current_parent_id = queue.get()
  71. else:
  72. break
  73.  
  74. return root_vertice
  75.  
  76. # размер графа (пусть и пострашнее, зато теперь без рекурсии)
  77. def calculate_width(vertice):
  78. if vertice == None: return 0
  79.  
  80. queue = Queue()
  81. current_vertice = vertice
  82.  
  83. width = 0
  84.  
  85. while True:
  86. width = width + 1
  87.  
  88. left = current_vertice['left']
  89. right = current_vertice['right']
  90.  
  91. if left != None:
  92. current_vertice = left
  93. if right != None:
  94. queue.put(right)
  95. elif right != None:
  96. current_vertice = right
  97. elif not queue.empty():
  98. current_vertice = queue.get()
  99. else:
  100. return width
  101.  
  102. def calculate_height(vertice):
  103. if vertice == None: return 0
  104.  
  105. queue = Queue()
  106. current_vertice = vertice
  107. current_height = 0
  108.  
  109. height = 0
  110.  
  111. while True:
  112. current_height = current_height + 1
  113. height = max(height, current_height)
  114.  
  115. left = current_vertice['left']
  116. right = current_vertice['right']
  117.  
  118. if left != None:
  119. current_vertice = left
  120.  
  121. if right != None:
  122. queue.put(( right, current_height ))
  123. elif right != None:
  124. current_vertice = right
  125. elif not queue.empty():
  126. current_vertice, current_height = queue.get()
  127. else:
  128. return height
  129.  
  130. def calculate_size(vertice):
  131. return calculate_width(vertice), calculate_height(vertice)
  132.  
  133. # рекурсивный расчёт координат вершин
  134. def calculate_positions(vertice, offset_x = 0, offset_y = -1):
  135. if vertice == None: return
  136.  
  137. # зачем-то ось Y направлена вверх, «против» графа, так что начнём отсчёт с
  138. # высоты и пойдём наверх
  139. if offset_y == -1: offset_y = calculate_height(vertice) - 1
  140.  
  141. queue = Queue()
  142. current_vertice = vertice
  143. current_offset_x = offset_x
  144. current_offset_y = offset_y
  145.  
  146. while True:
  147. # узкое место, подсчёт ширины для каждого потомка
  148. current_vertice['x'] = current_offset_x + calculate_width(current_vertice['left'])
  149. current_vertice['y'] = current_offset_y
  150.  
  151. left = current_vertice['left']
  152. right = current_vertice['right']
  153.  
  154. current_offset_y = current_offset_y - 1
  155.  
  156. if left != None:
  157. if right != None:
  158. queue.put(( right, current_vertice['x'] + 1, current_offset_y ))
  159. current_vertice = left
  160. elif right != None:
  161. current_offset_x = current_vertice['x'] + 1
  162. current_vertice = right
  163. elif not queue.empty():
  164. current_vertice, current_offset_x, current_offset_y = queue.get()
  165. else:
  166. return
  167.  
  168. # красивенький вывод
  169. # рекурсивен, так что не работает для больших деревьев
  170. def print_in_order(vertice):
  171. # если координаты ещё не были рассчитаны, рассчитаем
  172. if not 'x' in vertice: calculate_positions(vertice)
  173.  
  174. # размер графа
  175. height = calculate_height(vertice)
  176. width = calculate_width(vertice)
  177.  
  178. if width > 120:
  179. print('graph is too big')
  180. return
  181.  
  182. # создаём поле из «-1» размером с граф
  183. field = [ [ -1 for x in range(0, width) ] for x in
  184. list(range(0, calculate_height(vertice))) ]
  185.  
  186. # рекурсивно отмечаем вершину на поле
  187. def mark_vertice(vertice):
  188. if vertice == None: return
  189.  
  190. # опять же, переворачиваем ось Y
  191. field[height - 1 - vertice['y']][vertice['x']] = vertice['id']
  192. mark_vertice(vertice['left'])
  193. mark_vertice(vertice['right'])
  194.  
  195. mark_vertice(vertice)
  196.  
  197. # выводим поле (с пробелами вместо «-1»)
  198. print('\n'.join(''.join(
  199. ' ' if x == -1 else str(x) for x in y) for y in field))
  200.  
  201. # получаем координаты вершины
  202. def get_position_of(vertice, id):
  203. if vertice == None: return None
  204.  
  205. # если координаты ещё не были рассчитаны, рассчитаем
  206. if not 'x' in vertice: calculate_positions(vertice)
  207.  
  208. queue = Queue()
  209. current_vertice = vertice
  210.  
  211. while True:
  212. if current_vertice['id'] == id: return current_vertice['x'], current_vertice['y']
  213.  
  214. left = current_vertice['left']
  215. right = current_vertice['right']
  216.  
  217. if left != None:
  218. current_vertice = left
  219. if right != None:
  220. queue.put(right)
  221. elif right != None:
  222. current_vertice = right
  223. elif not queue.empty():
  224. current_vertice = queue.get()
  225. else:
  226. return None
  227.  
  228. root_vertice = solve_graph([
  229. [ 10, 5, 3 ],
  230. [ 2, 4 ],
  231. [ 4, 1 ],
  232. [ 0, 6 ],
  233. [ 7, 6 ],
  234. [ 8, 9 ],
  235. [ 4, 5 ],
  236. [ 6, 3 ],
  237. [ 3, 5 ],
  238. [ 3, 8 ]
  239. ])
  240.  
  241. print(root_vertice)
  242. print(calculate_size(root_vertice))
  243. print_in_order(root_vertice)
  244. print(get_position_of(root_vertice, 1))
  245. print(get_position_of(root_vertice, 3))
  246. print(get_position_of(root_vertice, 9))
  247.  
  248. root_vertice = solve_graph(
  249. [ [ 1000, 15, 3 ] if x < 0 else [ x, x + 1 ] for x in range(-1, 999) ]
  250. )
  251.  
  252.  
  253. print(calculate_width(root_vertice))
  254. print(calculate_height(root_vertice))
  255. calculate_positions(root_vertice)
  256.  
  257. print(get_position_of(root_vertice, 15))
  258. print(get_position_of(root_vertice, 9))
Advertisement
Add Comment
Please, Sign In to add comment