fork download
  1. # fields_and_stones_longest.py
  2. import random
  3. import time
  4. import sys
  5.  
  6. # Налаштування рекурсії
  7. sys.setrecursionlimit(10000)
  8.  
  9. # ------------------------
  10. # Генерація поля
  11. # 0 = поле ('.'), 1 = камінь ('#')
  12. # ------------------------
  13. def generate_field(N, M, p):
  14. grid = [[1 if random.random() < p else 0 for _ in range(M)] for _ in range(N)]
  15. grid[N-1][0] = 0 # старт (лівий нижній)
  16. grid[0][M-1] = 0 # фініш (правий верхній)
  17. return grid
  18.  
  19. # ------------------------
  20. # Коротка перевірка існування шляху (BFS) перед тривалим DFS
  21. # щоб не запускати довгий пошук коли шлях зовсім відсутній
  22. # ------------------------
  23. from collections import deque
  24. def exists_path_bfs(grid):
  25. N, M = len(grid), len(grid[0])
  26. start = (N-1,0)
  27. goal = (0, M-1)
  28. if grid[start[0]][start[1]] != 0 or grid[goal[0]][goal[1]] != 0:
  29. return False
  30. q = deque([start])
  31. vis = [[False]*M for _ in range(N)]
  32. vis[start[0]][start[1]] = True
  33. dirs = [(1,0),(-1,0),(0,1),(0,-1)]
  34. while q:
  35. r,c = q.popleft()
  36. if (r,c) == goal:
  37. return True
  38. for dr,dc in dirs:
  39. nr, nc = r+dr, c+dc
  40. if 0 <= nr < N and 0 <= nc < M and not vis[nr][nc] and grid[nr][nc] == 0:
  41. vis[nr][nc] = True
  42. q.append((nr,nc))
  43. return False
  44.  
  45. # ------------------------
  46. # Пошук найдовшого простого шляху (DFS з відкатом + таймаут)
  47. # Параметри:
  48. # time_limit - сек., скільки максимум шукати
  49. # randomize - чи випадково перемішувати порядок сусідів для різноманіття
  50. # Повертає: найкращий шлях як список клітин від старту до фінішу (включно) або None
  51. # ------------------------
  52. def longest_path_dfs(grid, time_limit=1.5, randomize=True):
  53. N, M = len(grid), len(grid[0])
  54. start = (N-1, 0)
  55. goal = (0, M-1)
  56. dirs = [(1,0), (0,1), (-1,0), (0,-1)] # порядок можна міняти
  57. best_path = None
  58. best_len = -1
  59. start_time = time.time()
  60. max_nodes = 10**6
  61. nodes = 0
  62.  
  63. # Пріоритет: спробуємо шукати більш глибоко — порядок сусідів можна перемішати
  64. import random as _rnd
  65.  
  66. visited = [[False]*M for _ in range(N)]
  67. path = []
  68.  
  69. def dfs(r,c):
  70. nonlocal best_len, best_path, nodes
  71. # таймаут/лиміт на відвідані вузли
  72. if time.time() - start_time > time_limit:
  73. return
  74. nodes += 1
  75. if nodes > max_nodes:
  76. return
  77.  
  78. # якщо дійшли до goal — оновити кращий шлях
  79. if (r,c) == goal:
  80. if len(path) > best_len:
  81. best_len = len(path)
  82. best_path = path.copy()
  83. # не повертаємось далі з goal (нам потрібно goal бути останнім)
  84. return
  85.  
  86. # Порядок сусідів: спочатку ті, що ведуть ближче до goal (гіпо), потім інші
  87. neighs = []
  88. for dr,dc in dirs:
  89. nr, nc = r+dr, c+dc
  90. if 0 <= nr < N and 0 <= nc < M and not visited[nr][nc] and grid[nr][nc] == 0:
  91. # не заходити в goal, якщо goal вже в path (не буде)
  92. # обчислимо евклідну відстань або манхеттен
  93. dist = abs(nr - goal[0]) + abs(nc - goal[1])
  94. neighs.append((dist, nr, nc))
  95. # сортуємо за зменшенням відстані -> спочатку ті, що далі від цілі, щоб робити довші «змійки»
  96. neighs.sort(reverse=True, key=lambda x: x[0])
  97. if randomize:
  98. # невелика випадкова перестановка серед тих з однаковою дистанцією
  99. i = 0
  100. while i < len(neighs):
  101. j = i
  102. while j < len(neighs) and neighs[j][0] == neighs[i][0]:
  103. j += 1
  104. # shuffle block [i, j)
  105. block = neighs[i:j]
  106. _rnd.shuffle(block)
  107. neighs[i:j] = block
  108. i = j
  109.  
  110. for _, nr, nc in neighs:
  111. # якщо досягли ліміту часу, виходимо
  112. if time.time() - start_time > time_limit:
  113. return
  114. # відвідуємо
  115. visited[nr][nc] = True
  116. path.append((nr,nc))
  117. dfs(nr,nc)
  118. # відкат
  119. path.pop()
  120. visited[nr][nc] = False
  121. # optional pruning: якщо знайшли шлях максимальної можливої довжини (всі поля), можна зупинитися
  122. # але ми не рахуємо тут максимально можливу глобальну довжину, тому пропускаємо
  123.  
  124. # початковий захід: старт має бути першою позицією у path
  125. if grid[start[0]][start[1]] != 0 or grid[goal[0]][goal[1]] != 0:
  126. return None
  127.  
  128. visited[start[0]][start[1]] = True
  129. path.append(start)
  130. dfs(start[0], start[1])
  131. # якщо нічого не знайдено (можливо шлях існував тільки прямий) — best_path може бути None
  132. visited[start[0]][start[1]] = False
  133. path.pop()
  134.  
  135. return best_path
  136.  
  137. # ------------------------
  138. # Вивід карти: пронумерований шлях (0 = старт), '.' для незораного, '#' для каменю
  139. # Клітинка має ширину під найбільший індекс
  140. # ------------------------
  141. def print_board_numbered(grid, path):
  142. N, M = len(grid), len(grid[0])
  143. step = {}
  144. if path:
  145. for i, cell in enumerate(path):
  146. step[cell] = i
  147.  
  148. max_step = max(step.values()) if step else 0
  149. width = max(3, len(str(max_step)) + 2)
  150.  
  151. def cell_str(s):
  152. return str(s).center(width)
  153.  
  154. print()
  155. for r in range(N):
  156. row_cells = []
  157. for c in range(M):
  158. if (r,c) in step:
  159. row_cells.append(cell_str(step[(r,c)]))
  160. elif grid[r][c] == 1:
  161. row_cells.append(cell_str("#"))
  162. else:
  163. row_cells.append(cell_str("."))
  164. print("".join(row_cells))
  165. print()
  166.  
  167. # ------------------------
  168. # MAIN (українською)
  169. # ------------------------
  170. def main():
  171. print("=== Поля і каміння — пошук довгого простого шляху (забезпечує, що фініт останній) ===")
  172. try:
  173. N = int(input("Введіть кількість рядків N (1..100): ").strip())
  174. M = int(input("Введіть кількість стовпців M (1..100): ").strip())
  175. except Exception:
  176. print("Некоректні N або M.")
  177. return
  178. if not (1 <= N <= 100 and 1 <= M <= 100):
  179. print("N і M повинні бути від 1 до 100.")
  180. return
  181.  
  182. try:
  183. p = float(input("Ймовірність каменю в клітинці (0..1), наприклад 0.25: ").strip())
  184. if not (0.0 <= p <= 1.0):
  185. raise ValueError()
  186. except Exception:
  187. print("Некоректне p — використовую 0.25")
  188. p = 0.25
  189.  
  190. try:
  191. tlim = float(input("Часовий ліміт пошуку в секундах (наприклад 1.5): ").strip())
  192. if tlim <= 0:
  193. tlim = 1.5
  194. except Exception:
  195. tlim = 1.5
  196.  
  197. regen = input("Якщо потрібно — регенерувати поле поки існує шлях? (т/н) [т]: ").strip().lower()
  198. regen_flag = (regen == "" or regen == "т" or regen == "y" or regen == "yes")
  199.  
  200. attempts = 0
  201. while True:
  202. attempts += 1
  203. grid = generate_field(N, M, p)
  204. if exists_path_bfs(grid):
  205. break
  206. if not regen_flag:
  207. break
  208. if attempts > 2000:
  209. print("Не вдалось згенерувати поле з шляхом за багато спроб. Спробуйте змінити p.")
  210. return
  211.  
  212. print("\nЗгенероване поле (вирівняне):")
  213. print_board_numbered(grid, None)
  214.  
  215. if not exists_path_bfs(grid):
  216. print("Шляху немає — завершую.")
  217. return
  218.  
  219. print(f"Починаємо пошук найдовшого простого шляху (таймаут = {tlim} сек)...")
  220. best = longest_path_dfs(grid, time_limit=tlim, randomize=True)
  221.  
  222. if not best:
  223. print("Не знайдено жодного шляху (неочікувано).")
  224. return
  225.  
  226. # best — шлях з старту до фінішу, простий, goal останній
  227. print(f"Знайдений шлях довжиною {len(best)} (0 = старт).")
  228. print("\nКарта з пронумерованим шляхом:")
  229. print_board_numbered(grid, best)
  230.  
  231. # Додатково: виведемо координати шляху у 1-based
  232. print("\nКроки шляху (1-based координати):")
  233. print([(r+1, c+1) for (r,c) in best])
  234.  
  235. if __name__ == "__main__":
  236. main()
  237.  
Success #stdin #stdout 1.6s 14380KB
stdin
25
25
0.25
1.5
т
stdout
=== Поля і каміння — пошук довгого простого шляху (забезпечує, що фініт останній) ===
Введіть кількість рядків N (1..100): Введіть кількість стовпців M (1..100): Ймовірність каменю в клітинці (0..1), наприклад 0.25: Часовий ліміт пошуку в секундах (наприклад 1.5): Якщо потрібно — регенерувати поле поки існує шлях? (т/н) [т]: 
Згенероване поле (вирівняне):

 .  .  .  .  #  .  .  #  .  #  .  .  .  .  #  .  .  .  #  .  .  .  #  .  . 
 #  .  .  #  .  .  .  .  .  #  .  #  .  .  #  #  .  .  .  .  .  .  .  .  . 
 #  .  #  .  #  .  .  .  .  .  .  #  .  #  .  .  #  #  .  .  .  .  .  .  . 
 .  .  .  .  #  .  .  #  .  .  .  .  .  .  .  .  #  .  .  .  #  #  .  #  . 
 #  .  #  .  #  #  .  .  .  .  .  #  .  .  #  .  .  .  .  .  .  .  #  .  . 
 .  #  .  .  .  .  .  .  .  .  #  #  .  .  .  .  .  .  #  #  #  #  .  .  . 
 .  .  .  .  #  .  #  #  .  .  .  #  .  .  .  #  .  .  .  .  .  .  .  #  . 
 .  .  #  #  .  .  .  .  .  .  .  #  #  .  #  .  .  .  #  .  .  .  .  #  . 
 #  #  .  .  .  .  .  .  .  .  .  .  #  .  .  #  .  .  .  .  .  #  .  .  . 
 .  .  .  #  #  .  .  .  .  .  .  .  .  .  #  .  #  .  .  .  .  .  #  #  . 
 #  .  .  .  .  #  .  .  .  .  #  #  .  #  .  #  #  .  .  .  .  .  .  .  . 
 #  .  .  .  .  .  .  .  .  .  .  .  .  #  .  .  .  #  .  #  .  #  #  .  . 
 #  .  .  #  #  .  .  #  #  #  .  .  .  .  .  .  .  .  .  .  .  #  .  #  . 
 .  .  #  .  .  .  .  .  .  .  .  .  .  .  .  #  .  #  #  .  .  .  .  .  . 
 .  .  .  .  #  .  .  .  #  .  .  .  .  #  .  .  #  .  .  .  .  .  .  .  # 
 .  #  .  .  #  #  .  #  .  #  .  #  #  #  .  .  .  .  #  .  .  #  .  .  . 
 .  #  #  .  .  .  .  #  .  .  .  .  .  #  .  #  .  .  .  .  .  #  .  .  . 
 .  .  .  .  .  .  #  .  #  .  .  #  .  #  .  .  .  .  .  #  .  .  .  #  . 
 .  .  #  .  .  .  .  .  .  .  #  .  #  .  .  .  .  .  #  .  .  .  .  .  . 
 .  .  .  .  .  #  .  #  .  #  .  .  .  .  .  #  .  #  .  .  #  #  .  .  . 
 #  .  .  #  .  .  .  #  .  .  .  #  #  .  .  .  .  #  .  .  #  .  .  .  # 
 #  .  .  #  .  .  .  #  #  .  .  .  .  .  #  .  .  .  #  .  .  .  #  .  . 
 .  #  .  .  .  #  #  .  .  #  .  #  #  .  #  .  .  #  .  .  .  .  .  .  # 
 .  .  .  .  .  .  .  .  .  #  .  .  .  .  .  #  .  #  .  .  .  .  .  .  . 
 .  .  #  #  .  #  .  .  .  .  #  .  .  #  .  #  .  .  .  .  .  .  .  .  . 

Починаємо пошук найдовшого простого шляху (таймаут = 1.5 сек)...
Знайдений шлях довжиною 317 (0 = старт).

Карта з пронумерованим шляхом:

  .    .    .    .    #   213  214   #    .    #    .    .    .    .    #    .    .    .    #   309  310   .    #    .   316 
  #    .    .    #    .   212  215  218  219   #    .    #    .    .    #    #    .    .   307  308  311  312  313  314  315 
  #    .    #    .    #   211  216  217  220   .    .    #    .    #   250  251   #    #   306  299  298  297  296  295  294 
  .    .    .    .    #   210  209   #   221  236  237  238  239  248  249  252   #   304  305  300   #    #    .    #   293 
  #    .    #    .    #    #   208  207  222  235   .    #   240  247   #   253   .   303  302  301   .    .    #    .   292 
  .    #    .    .    .   204  205  206  223  234   #    #   241  246  245  254  255   .    #    #    #    #   289  290  291 
  .    .    .    .    #   203   #    #   224  233   .    #   242  243  244   #   256   .    .   285  286  287  288   #    .  
  .    .    #    #    .   202  201   .   225  232  231   #    #    .    #    .   257   .    #   284  283  282  281   #    .  
  #    #    58   59   60   61  200  199  226  227  230   .    #    .    .    #   258  259  264  265   .    #   280  279  278 
  .    .    57   #    #    62   63  198  197  228  229   .    .    .    #    .    #   260  263  266  269  270   #    #   277 
  #    55   56   .    .    #    64  195  196   .    #    #    .    #    .    #    #   261  262  267  268  271  272  273  276 
  #    54   51   50   49   48   65  194  193  192  191   .    .    #    .    .    .    #    .    #    .    #    #   274  275 
  #    53   52   #    #    47   66   #    #    #   190  189  188  187  186  185  184  183  182  181   .    #    .    #    .  
  .    .    #    .    .    46   67   68   69   70   .    .    .    .    .    #    .    #    #   180  179  178  177  176   .  
  20   21   22   .    #    45   44   .    #    71   72   .    .    #    .    .    #   165  166  167  170  171  172  175   #  
  19   #    23   24   #    #    43   #    .    #    73   #    #    #   159  160  161  164   #   168  169   #   173  174   .  
  18   #    #    25   40   41   42   #    .    75   74   .    .    #   158   #   162  163  150  149  148   #   144  143  142 
  17   16   .    26   39   .    #    .    #    76   .    #    .    #   157  156   .   152  151   #   147  146  145   #   141 
  14   15   #    27   38   37   36   .    78   77   #    .    #    95   96  155  154  153   #   121  122  123  124   .   140 
  13   12   .    28   29   #    35   #    79   #    .    .    .    94   97   #    .    #   119  120   #    #   125  138  139 
  #    11   .    #    30   33   34   #    80   81   .    #    #    93   98   99   .    #   118  117   #   127  126  137   #  
  #    10   9    #    31   32   .    #    #    82   83   .    .    92   #   100   .    .    #   116  115  128   #   136   .  
  .    #    8    7    6    #    #    .    .    #    84   #    #    91   #   101  102   #   108  109  114  129   .   135   #  
  .    2    3    4    5    .    .    .    .    #    85   86   89   90   .    #   103   #   107  110  113  130  133  134   .  
  0    1    #    #    .    #    .    .    .    .    #    87   88   #    .    #   104  105  106  111  112  131  132   .    .  


Кроки шляху (1-based координати):
[(25, 1), (25, 2), (24, 2), (24, 3), (24, 4), (24, 5), (23, 5), (23, 4), (23, 3), (22, 3), (22, 2), (21, 2), (20, 2), (20, 1), (19, 1), (19, 2), (18, 2), (18, 1), (17, 1), (16, 1), (15, 1), (15, 2), (15, 3), (16, 3), (16, 4), (17, 4), (18, 4), (19, 4), (20, 4), (20, 5), (21, 5), (22, 5), (22, 6), (21, 6), (21, 7), (20, 7), (19, 7), (19, 6), (19, 5), (18, 5), (17, 5), (17, 6), (17, 7), (16, 7), (15, 7), (15, 6), (14, 6), (13, 6), (12, 6), (12, 5), (12, 4), (12, 3), (13, 3), (13, 2), (12, 2), (11, 2), (11, 3), (10, 3), (9, 3), (9, 4), (9, 5), (9, 6), (10, 6), (10, 7), (11, 7), (12, 7), (13, 7), (14, 7), (14, 8), (14, 9), (14, 10), (15, 10), (15, 11), (16, 11), (17, 11), (17, 10), (18, 10), (19, 10), (19, 9), (20, 9), (21, 9), (21, 10), (22, 10), (22, 11), (23, 11), (24, 11), (24, 12), (25, 12), (25, 13), (24, 13), (24, 14), (23, 14), (22, 14), (21, 14), (20, 14), (19, 14), (19, 15), (20, 15), (21, 15), (21, 16), (22, 16), (23, 16), (23, 17), (24, 17), (25, 17), (25, 18), (25, 19), (24, 19), (23, 19), (23, 20), (24, 20), (25, 20), (25, 21), (24, 21), (23, 21), (22, 21), (22, 20), (21, 20), (21, 19), (20, 19), (20, 20), (19, 20), (19, 21), (19, 22), (19, 23), (20, 23), (21, 23), (21, 22), (22, 22), (23, 22), (24, 22), (25, 22), (25, 23), (24, 23), (24, 24), (23, 24), (22, 24), (21, 24), (20, 24), (20, 25), (19, 25), (18, 25), (17, 25), (17, 24), (17, 23), (18, 23), (18, 22), (18, 21), (17, 21), (17, 20), (17, 19), (18, 19), (18, 18), (19, 18), (19, 17), (19, 16), (18, 16), (18, 15), (17, 15), (16, 15), (16, 16), (16, 17), (17, 17), (17, 18), (16, 18), (15, 18), (15, 19), (15, 20), (16, 20), (16, 21), (15, 21), (15, 22), (15, 23), (16, 23), (16, 24), (15, 24), (14, 24), (14, 23), (14, 22), (14, 21), (14, 20), (13, 20), (13, 19), (13, 18), (13, 17), (13, 16), (13, 15), (13, 14), (13, 13), (13, 12), (13, 11), (12, 11), (12, 10), (12, 9), (12, 8), (11, 8), (11, 9), (10, 9), (10, 8), (9, 8), (9, 7), (8, 7), (8, 6), (7, 6), (6, 6), (6, 7), (6, 8), (5, 8), (5, 7), (4, 7), (4, 6), (3, 6), (2, 6), (1, 6), (1, 7), (2, 7), (3, 7), (3, 8), (2, 8), (2, 9), (3, 9), (4, 9), (5, 9), (6, 9), (7, 9), (8, 9), (9, 9), (9, 10), (10, 10), (10, 11), (9, 11), (8, 11), (8, 10), (7, 10), (6, 10), (5, 10), (4, 10), (4, 11), (4, 12), (4, 13), (5, 13), (6, 13), (7, 13), (7, 14), (7, 15), (6, 15), (6, 14), (5, 14), (4, 14), (4, 15), (3, 15), (3, 16), (4, 16), (5, 16), (6, 16), (6, 17), (7, 17), (8, 17), (9, 17), (9, 18), (10, 18), (11, 18), (11, 19), (10, 19), (9, 19), (9, 20), (10, 20), (11, 20), (11, 21), (10, 21), (10, 22), (11, 22), (11, 23), (11, 24), (12, 24), (12, 25), (11, 25), (10, 25), (9, 25), (9, 24), (9, 23), (8, 23), (8, 22), (8, 21), (8, 20), (7, 20), (7, 21), (7, 22), (7, 23), (6, 23), (6, 24), (6, 25), (5, 25), (4, 25), (3, 25), (3, 24), (3, 23), (3, 22), (3, 21), (3, 20), (4, 20), (5, 20), (5, 19), (5, 18), (4, 18), (4, 19), (3, 19), (2, 19), (2, 20), (1, 20), (1, 21), (2, 21), (2, 22), (2, 23), (2, 24), (2, 25), (1, 25)]