Advertisement
Guest User

Untitled

a guest
Apr 23rd, 2018
55
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 23.13 KB | None | 0 0
  1. Pocetok = input()
  2. Stanica1 = input()
  3. Stanica2 = input()
  4. Kraj = input()
  5.  
  6.  
  7. # Python modul vo koj se implementirani algoritmite za neinformirano i informirano prebaruvanje
  8.  
  9. # ______________________________________________________________________________________________
  10. # Improtiranje na dopolnitelno potrebni paketi za funkcioniranje na kodovite
  11.  
  12. import sys
  13. import bisect
  14.  
  15. infinity = float('inf') # sistemski definirana vrednost za beskonecnost
  16.  
  17.  
  18. # ______________________________________________________________________________________________
  19. # Definiranje na pomosni strukturi za cuvanje na listata na generirani, no neprovereni jazli
  20.  
  21. class Queue:
  22. """Queue is an abstract class/interface. There are three types:
  23. Stack(): A Last In First Out Queue.
  24. FIFOQueue(): A First In First Out Queue.
  25. PriorityQueue(order, f): Queue in sorted order (default min-first).
  26. Each type supports the following methods and functions:
  27. q.append(item) -- add an item to the queue
  28. q.extend(items) -- equivalent to: for item in items: q.append(item)
  29. q.pop() -- return the top item from the queue
  30. len(q) -- number of items in q (also q.__len())
  31. item in q -- does q contain item?
  32. Note that isinstance(Stack(), Queue) is false, because we implement stacks
  33. as lists. If Python ever gets interfaces, Queue will be an interface."""
  34.  
  35. def __init__(self):
  36. raise NotImplementedError
  37.  
  38. def extend(self, items):
  39. for item in items:
  40. self.append(item)
  41.  
  42.  
  43. def Stack():
  44. """A Last-In-First-Out Queue."""
  45. return []
  46.  
  47.  
  48. class FIFOQueue(Queue):
  49. """A First-In-First-Out Queue."""
  50.  
  51. def __init__(self):
  52. self.A = []
  53. self.start = 0
  54.  
  55. def append(self, item):
  56. self.A.append(item)
  57.  
  58. def __len__(self):
  59. return len(self.A) - self.start
  60.  
  61. def extend(self, items):
  62. self.A.extend(items)
  63.  
  64. def pop(self):
  65. e = self.A[self.start]
  66. self.start += 1
  67. if self.start > 5 and self.start > len(self.A) / 2:
  68. self.A = self.A[self.start:]
  69. self.start = 0
  70. return e
  71.  
  72. def __contains__(self, item):
  73. return item in self.A[self.start:]
  74.  
  75.  
  76. class PriorityQueue(Queue):
  77. """A queue in which the minimum (or maximum) element (as determined by f and
  78. order) is returned first. If order is min, the item with minimum f(x) is
  79. returned first; if order is max, then it is the item with maximum f(x).
  80. Also supports dict-like lookup. This structure will be most useful in informed searches"""
  81.  
  82. def __init__(self, order=min, f=lambda x: x):
  83. self.A = []
  84. self.order = order
  85. self.f = f
  86.  
  87. def append(self, item):
  88. bisect.insort(self.A, (self.f(item), item))
  89.  
  90. def __len__(self):
  91. return len(self.A)
  92.  
  93. def pop(self):
  94. if self.order == min:
  95. return self.A.pop(0)[1]
  96. else:
  97. return self.A.pop()[1]
  98.  
  99. def __contains__(self, item):
  100. return any(item == pair[1] for pair in self.A)
  101.  
  102. def __getitem__(self, key):
  103. for _, item in self.A:
  104. if item == key:
  105. return item
  106.  
  107. def __delitem__(self, key):
  108. for i, (value, item) in enumerate(self.A):
  109. if item == key:
  110. self.A.pop(i)
  111.  
  112.  
  113. # ______________________________________________________________________________________________
  114. # Definiranje na klasa za strukturata na problemot koj ke go resavame so prebaruvanje
  115. # Klasata Problem e apstraktna klasa od koja pravime nasleduvanje za definiranje na osnovnite karakteristiki
  116. # na sekoj eden problem sto sakame da go resime
  117.  
  118.  
  119. class Problem:
  120. """The abstract class for a formal problem. You should subclass this and
  121. implement the method successor, and possibly __init__, goal_test, and
  122. path_cost. Then you will create instances of your subclass and solve them
  123. with the various search functions."""
  124.  
  125. def __init__(self, initial, goal=None):
  126. """The constructor specifies the initial state, and possibly a goal
  127. state, if there is a unique goal. Your subclass's constructor can add
  128. other arguments."""
  129. self.initial = initial
  130. self.goal = goal
  131.  
  132. def successor(self, state):
  133. """Given a state, return a dictionary of {action : state} pairs reachable
  134. from this state. If there are many successors, consider an iterator
  135. that yields the successors one at a time, rather than building them
  136. all at once. Iterators will work fine within the framework. Yielding is not supported in Python 2.7"""
  137. raise NotImplementedError
  138.  
  139. def actions(self, state):
  140. """Given a state, return a list of all actions possible from that state"""
  141. raise NotImplementedError
  142.  
  143. def result(self, state, action):
  144. """Given a state and action, return the resulting state"""
  145. raise NotImplementedError
  146.  
  147. def goal_test(self, state):
  148. """Return True if the state is a goal. The default method compares the
  149. state to self.goal, as specified in the constructor. Implement this
  150. method if checking against a single self.goal is not enough."""
  151. return state == self.goal
  152.  
  153. def path_cost(self, c, state1, action, state2):
  154. """Return the cost of a solution path that arrives at state2 from
  155. state1 via action, assuming cost c to get up to state1. If the problem
  156. is such that the path doesn't matter, this function will only look at
  157. state2. If the path does matter, it will consider c and maybe state1
  158. and action. The default method costs 1 for every step in the path."""
  159. return c + 1
  160.  
  161. def value(self):
  162. """For optimization problems, each state has a value. Hill-climbing
  163. and related algorithms try to maximize this value."""
  164. raise NotImplementedError
  165.  
  166.  
  167. # ______________________________________________________________________________
  168. # Definiranje na klasa za strukturata na jazel od prebaruvanje
  169. # Klasata Node ne se nasleduva
  170.  
  171. class Node:
  172. """A node in a search tree. Contains a pointer to the parent (the node
  173. that this is a successor of) and to the actual state for this node. Note
  174. that if a state is arrived at by two paths, then there are two nodes with
  175. the same state. Also includes the action that got us to this state, and
  176. the total path_cost (also known as g) to reach the node. Other functions
  177. may add an f and h value; see best_first_graph_search and astar_search for
  178. an explanation of how the f and h values are handled. You will not need to
  179. subclass this class."""
  180.  
  181. def __init__(self, state, parent=None, action=None, path_cost=0):
  182. "Create a search tree Node, derived from a parent by an action."
  183. self.state = state
  184. self.parent = parent
  185. self.action = action
  186. self.path_cost = path_cost
  187. self.depth = 0
  188. if parent:
  189. self.depth = parent.depth + 1
  190.  
  191. def __repr__(self):
  192. return "<Node %s>" % (self.state,)
  193.  
  194. def __lt__(self, node):
  195. return self.state < node.state
  196.  
  197. def expand(self, problem):
  198. "List the nodes reachable in one step from this node."
  199. return [self.child_node(problem, action)
  200. for action in problem.actions(self.state)]
  201.  
  202. def child_node(self, problem, action):
  203. "Return a child node from this node"
  204. next = problem.result(self.state, action)
  205. return Node(next, self, action,
  206. problem.path_cost(self.path_cost, self.state,
  207. action, next))
  208.  
  209. def solution(self):
  210. "Return the sequence of actions to go from the root to this node."
  211. return [node.action for node in self.path()[1:]]
  212.  
  213. def solve(self):
  214. "Return the sequence of states to go from the root to this node."
  215. return [node.state for node in self.path()[0:]]
  216.  
  217. def path(self):
  218. "Return a list of nodes forming the path from the root to this node."
  219. x, result = self, []
  220. while x:
  221. result.append(x)
  222. x = x.parent
  223. return list(reversed(result))
  224.  
  225. # We want for a queue of nodes in breadth_first_search or
  226. # astar_search to have no duplicated states, so we treat nodes
  227. # with the same state as equal. [Problem: this may not be what you
  228. # want in other contexts.]
  229.  
  230. def __eq__(self, other):
  231. return isinstance(other, Node) and self.state == other.state
  232.  
  233. def __hash__(self):
  234. return hash(self.state)
  235.  
  236.  
  237. # ________________________________________________________________________________________________________
  238. #Neinformirano prebaruvanje vo ramki na drvo
  239. #Vo ramki na drvoto ne razresuvame jamki
  240.  
  241. def tree_search(problem, fringe):
  242. """Search through the successors of a problem to find a goal.
  243. The argument fringe should be an empty queue."""
  244. fringe.append(Node(problem.initial))
  245. while fringe:
  246. node = fringe.pop()
  247.  
  248. if problem.goal_test(node.state):
  249. return node
  250. fringe.extend(node.expand(problem))
  251. return None
  252.  
  253.  
  254. def breadth_first_tree_search(problem):
  255. "Search the shallowest nodes in the search tree first."
  256. return tree_search(problem, FIFOQueue())
  257.  
  258.  
  259. def depth_first_tree_search(problem):
  260. "Search the deepest nodes in the search tree first."
  261. return tree_search(problem, Stack())
  262.  
  263.  
  264. # ________________________________________________________________________________________________________
  265. #Neinformirano prebaruvanje vo ramki na graf
  266. #Osnovnata razlika e vo toa sto ovde ne dozvoluvame jamki t.e. povtoruvanje na sostojbi
  267.  
  268. def graph_search(problem, fringe):
  269. """Search through the successors of a problem to find a goal.
  270. The argument fringe should be an empty queue.
  271. If two paths reach a state, only use the best one."""
  272. closed = {}
  273. fringe.append(Node(problem.initial))
  274. while fringe:
  275. node = fringe.pop()
  276. if problem.goal_test(node.state):
  277. return node
  278. if node.state not in closed:
  279. closed[node.state] = True
  280. fringe.extend(node.expand(problem))
  281. return None
  282.  
  283.  
  284. def breadth_first_graph_search(problem):
  285. "Search the shallowest nodes in the search tree first."
  286. return graph_search(problem, FIFOQueue())
  287.  
  288.  
  289. def depth_first_graph_search(problem):
  290. "Search the deepest nodes in the search tree first."
  291. return graph_search(problem, Stack())
  292.  
  293.  
  294. def uniform_cost_search(problem):
  295. "Search the nodes in the search tree with lowest cost first."
  296. return graph_search(problem, PriorityQueue(lambda a, b: a.path_cost < b.path_cost))
  297.  
  298.  
  299. def depth_limited_search(problem, limit=50):
  300. "depth first search with limited depth"
  301.  
  302. def recursive_dls(node, problem, limit):
  303. "helper function for depth limited"
  304. cutoff_occurred = False
  305. if problem.goal_test(node.state):
  306. return node
  307. elif node.depth == limit:
  308. return 'cutoff'
  309. else:
  310. for successor in node.expand(problem):
  311. result = recursive_dls(successor, problem, limit)
  312. if result == 'cutoff':
  313. cutoff_occurred = True
  314. elif result != None:
  315. return result
  316. if cutoff_occurred:
  317. return 'cutoff'
  318. else:
  319. return None
  320.  
  321. # Body of depth_limited_search:
  322. return recursive_dls(Node(problem.initial), problem, limit)
  323.  
  324.  
  325. def iterative_deepening_search(problem):
  326.  
  327. for depth in xrange(sys.maxint):
  328. result = depth_limited_search(problem, depth)
  329. if result is not 'cutoff':
  330. return result
  331.  
  332.  
  333. # ________________________________________________________________________________________________________
  334. #Pomosna funkcija za informirani prebaruvanja
  335. #So pomos na ovaa funkcija gi keshirame rezultatite od funkcijata na evaluacija
  336.  
  337. def memoize(fn, slot=None):
  338. """Memoize fn: make it remember the computed value for any argument list.
  339. If slot is specified, store result in that slot of first argument.
  340. If slot is false, store results in a dictionary."""
  341. if slot:
  342. def memoized_fn(obj, *args):
  343. if hasattr(obj, slot):
  344. return getattr(obj, slot)
  345. else:
  346. val = fn(obj, *args)
  347. setattr(obj, slot, val)
  348. return val
  349. else:
  350. def memoized_fn(*args):
  351. if not memoized_fn.cache.has_key(args):
  352. memoized_fn.cache[args] = fn(*args)
  353. return memoized_fn.cache[args]
  354.  
  355. memoized_fn.cache = {}
  356. return memoized_fn
  357.  
  358.  
  359. # ________________________________________________________________________________________________________
  360. #Informirano prebaruvanje vo ramki na graf
  361.  
  362. def best_first_graph_search(problem, f):
  363. """Search the nodes with the lowest f scores first.
  364. You specify the function f(node) that you want to minimize; for example,
  365. if f is a heuristic estimate to the goal, then we have greedy best
  366. first search; if f is node.depth then we have breadth-first search.
  367. There is a subtlety: the line "f = memoize(f, 'f')" means that the f
  368. values will be cached on the nodes as they are computed. So after doing
  369. a best first search you can examine the f values of the path returned."""
  370.  
  371. f = memoize(f, 'f')
  372. node = Node(problem.initial)
  373. if problem.goal_test(node.state):
  374. return node
  375. frontier = PriorityQueue(min, f)
  376. frontier.append(node)
  377. explored = set()
  378. while frontier:
  379. node = frontier.pop()
  380. if problem.goal_test(node.state):
  381. return node
  382. explored.add(node.state)
  383. for child in node.expand(problem):
  384. if child.state not in explored and child not in frontier:
  385. frontier.append(child)
  386. elif child in frontier:
  387. incumbent = frontier[child]
  388. if f(child) < f(incumbent):
  389. del frontier[incumbent]
  390. frontier.append(child)
  391. return None
  392.  
  393.  
  394. def greedy_best_first_graph_search(problem, h=None):
  395. "Greedy best-first search is accomplished by specifying f(n) = h(n)"
  396. h = memoize(h or problem.h, 'h')
  397. return best_first_graph_search(problem, h)
  398.  
  399.  
  400. def astar_search(problem, h=None):
  401. "A* search is best-first graph search with f(n) = g(n)+h(n)."
  402. h = memoize(h or problem.h, 'h')
  403. return best_first_graph_search(problem, lambda n: n.path_cost + h(n))
  404.  
  405.  
  406. # ________________________________________________________________________________________________________
  407. #Dopolnitelni prebaruvanja
  408. #Recursive_best_first_search e implementiran
  409. #Kako zadaca za studentite da gi implementiraat SMA* i IDA*
  410.  
  411. def recursive_best_first_search(problem, h=None):
  412. h = memoize(h or problem.h, 'h')
  413.  
  414. def RBFS(problem, node, flimit):
  415. if problem.goal_test(node.state):
  416. return node, 0 # (The second value is immaterial)
  417. successors = node.expand(problem)
  418. if len(successors) == 0:
  419. return None, infinity
  420. for s in successors:
  421. s.f = max(s.path_cost + h(s), node.f)
  422. while True:
  423. # Order by lowest f value
  424. successors.sort(key=lambda x: x.f)
  425. best = successors[0]
  426. if best.f > flimit:
  427. return None, best.f
  428. if len(successors) > 1:
  429. alternative = successors[1].f
  430. else:
  431. alternative = infinity
  432. result, best.f = RBFS(problem, best, min(flimit, alternative))
  433. if result is not None:
  434. return result, best.f
  435.  
  436. node = Node(problem.initial)
  437. node.f = h(node)
  438. result, bestf = RBFS(problem, node, infinity)
  439. return result
  440.  
  441.  
  442. # Graphs and Graph Problems
  443. import math
  444.  
  445. def distance(a, b):
  446. """The distance between two (x, y) points."""
  447. return math.hypot((a[0] - b[0]), (a[1] - b[1]))
  448.  
  449.  
  450. class Graph:
  451.  
  452. """A graph connects nodes (verticies) by edges (links). Each edge can also
  453. have a length associated with it. The constructor call is something like:
  454. g = Graph({'A': {'B': 1, 'C': 2})
  455. this makes a graph with 3 nodes, A, B, and C, with an edge of length 1 from
  456. A to B, and an edge of length 2 from A to C. You can also do:
  457. g = Graph({'A': {'B': 1, 'C': 2}, directed=False)
  458. This makes an undirected graph, so inverse links are also added. The graph
  459. stays undirected; if you add more links with g.connect('B', 'C', 3), then
  460. inverse link is also added. You can use g.nodes() to get a list of nodes,
  461. g.get('A') to get a dict of links out of A, and g.get('A', 'B') to get the
  462. length of the link from A to B. 'Lengths' can actually be any object at
  463. all, and nodes can be any hashable object."""
  464.  
  465. def __init__(self, dict=None, directed=True):
  466. self.dict = dict or {}
  467. self.directed = directed
  468. if not directed:
  469. self.make_undirected()
  470.  
  471. def make_undirected(self):
  472. """Make a digraph into an undirected graph by adding symmetric edges."""
  473. for a in list(self.dict.keys()):
  474. for (b, dist) in self.dict[a].items():
  475. self.connect1(b, a, dist)
  476.  
  477. def connect(self, A, B, distance=1):
  478. """Add a link from A and B of given distance, and also add the inverse
  479. link if the graph is undirected."""
  480. self.connect1(A, B, distance)
  481. if not self.directed:
  482. self.connect1(B, A, distance)
  483.  
  484. def connect1(self, A, B, distance):
  485. """Add a link from A to B of given distance, in one direction only."""
  486. self.dict.setdefault(A, {})[B] = distance
  487.  
  488. def get(self, a, b=None):
  489. """Return a link distance or a dict of {node: distance} entries.
  490. .get(a,b) returns the distance or None;
  491. .get(a) returns a dict of {node: distance} entries, possibly {}."""
  492. links = self.dict.setdefault(a, {})
  493. if b is None:
  494. return links
  495. else:
  496. return links.get(b)
  497.  
  498. def nodes(self):
  499. """Return a list of nodes in the graph."""
  500. return list(self.dict.keys())
  501.  
  502.  
  503. def UndirectedGraph(dict=None):
  504. """Build a Graph where every edge (including future ones) goes both ways."""
  505. return Graph(dict=dict, directed=False)
  506.  
  507.  
  508. def RandomGraph(nodes=list(range(10)), min_links=2, width=400, height=300,
  509. curvature=lambda: random.uniform(1.1, 1.5)):
  510. """Construct a random graph, with the specified nodes, and random links.
  511. The nodes are laid out randomly on a (width x height) rectangle.
  512. Then each node is connected to the min_links nearest neighbors.
  513. Because inverse links are added, some nodes will have more connections.
  514. The distance between nodes is the hypotenuse times curvature(),
  515. where curvature() defaults to a random number between 1.1 and 1.5."""
  516. g = UndirectedGraph()
  517. g.locations = {}
  518. # Build the cities
  519. for node in nodes:
  520. g.locations[node] = (random.randrange(width), random.randrange(height))
  521. # Build roads from each city to at least min_links nearest neighbors.
  522. for i in range(min_links):
  523. for node in nodes:
  524. if len(g.get(node)) < min_links:
  525. here = g.locations[node]
  526.  
  527. def distance_to_node(n):
  528. if n is node or g.get(node, n):
  529. return infinity
  530. return distance(g.locations[n], here)
  531. neighbor = argmin(nodes, key=distance_to_node)
  532. d = distance(g.locations[neighbor], here) * curvature()
  533. g.connect(node, neighbor, int(d))
  534. return g
  535.  
  536. class GraphProblem(Problem):
  537.  
  538. """The problem of searching a graph from one node to another."""
  539.  
  540. def __init__(self, initial, goal, graph):
  541. Problem.__init__(self, initial, goal)
  542. self.graph = graph
  543.  
  544. def actions(self, A):
  545. """The actions at a graph node are just its neighbors."""
  546. return list(self.graph.get(A).keys())
  547.  
  548. def result(self, state, action):
  549. """The result of going to a neighbor is just that neighbor."""
  550. return action
  551.  
  552. def path_cost(self, cost_so_far, A, action, B):
  553. return cost_so_far + (self.graph.get(A, B) or infinity)
  554.  
  555. def h(self, node):
  556. """h function is straight-line distance from a node's state to goal."""
  557. locs = getattr(self.graph, 'locations', None)
  558. if locs:
  559. return int(distance(locs[node.state], locs[self.goal]))
  560. else:
  561. return infinity
  562.  
  563.  
  564.  
  565. ABdistance = distance((2,1),(2,4))
  566. BIdistance = distance((2,4),(8,5))
  567. BCdistance = distance((2,4),(2,10))
  568. HIdistance = distance((8,1),(8,5))
  569. IJdistance = distance((8,5),(8,8))
  570. FCdistance = distance((5,9),(2,10))
  571. GCdistance = distance((4,11),(2,10))
  572. CDdistance = distance((2,10),(2,15))
  573. FGdistance = distance((5,9),(4,11))
  574. FJdistance = distance((5,9),(8,8))
  575. KGdistance = distance((8,13),(4,11))
  576. LKdistance = distance((8,15),(8,13))
  577. DEdistance = distance((2,15),(2,19))
  578. DLdistance = distance((2,15),(8,15))
  579. LMdistance = distance((8,15),(8,19))
  580.  
  581.  
  582.  
  583.  
  584. graph = UndirectedGraph({
  585. "B": {"A": ABdistance, "I": BIdistance, "C": BCdistance},
  586. "I": {"H": HIdistance, "J": IJdistance},
  587. "C": {"F": FCdistance, "G": GCdistance, "D": CDdistance},
  588. "F": {"G": FGdistance, "J": FJdistance},
  589. "K": {"G": KGdistance, "L": LKdistance},
  590. "D": {"E": DEdistance, "L": DLdistance},
  591. "M": {"L": LMdistance}
  592. })
  593.  
  594.  
  595. graph.locations = dict(
  596. A = (2,1) , B = (2,4) , C = (2,10) ,
  597. D = (2,15) , E = (2,19) , F = (5,9) ,
  598. G = (4,11) , H = (8,1) , I = (8,5),
  599. J = (8,8) , K = (8,13) , L = (8,15),
  600. M = (8,19))
  601.  
  602.  
  603.  
  604.  
  605.  
  606. prvaProblem1 = GraphProblem(Pocetok,Stanica1,graph)
  607. prvaProblem2 = GraphProblem(Stanica1,Kraj,graph)
  608.  
  609. prvaStanica1 = astar_search(prvaProblem1)
  610. prvaStanica2 = astar_search(prvaProblem2)
  611.  
  612. prvaStanicaDolzina1 = prvaStanica1.path_cost
  613. prvaStanicaDolzina2 = prvaStanica2.path_cost
  614.  
  615. dolzina1 = prvaStanicaDolzina1 + prvaStanicaDolzina2
  616.  
  617. vtoraProblem1 = GraphProblem(Pocetok,Stanica2,graph)
  618. vtoraProblem2= GraphProblem(Stanica2,Kraj,graph)
  619.  
  620. vtoraStanica1 = astar_search(vtoraProblem1)
  621. vtoraStanica2 = astar_search(vtoraProblem2)
  622.  
  623. vtoraStanicaDolzina1 = vtoraStanica1.path_cost
  624. vtoraStanicaDolzina2 = vtoraStanica2.path_cost
  625.  
  626. dolzina2 = vtoraStanicaDolzina1 + vtoraStanicaDolzina2
  627.  
  628.  
  629.  
  630. if(dolzina1<dolzina2):
  631. prvaStanica1 = astar_search(prvaProblem1).solve()
  632. prvaStanica2 = astar_search(prvaProblem2).solve()
  633. rez = prvaStanica1 + prvaStanica2[1:len(prvaStanica2)]
  634. print rez
  635. elif(dolzina1>dolzina2):
  636. vtoraStanica1 = astar_search(vtoraProblem1).solve()
  637. vtoraStanica2 = astar_search(vtoraProblem2).solve()
  638. rez = vtoraStanica1 + vtoraStanica2[1:len(vtoraStanica2)]
  639. print rez
  640. else:
  641. prvaStanica1 = astar_search(prvaProblem1).solve()
  642. prvaStanica2 = astar_search(prvaProblem2).solve()
  643. rez = prvaStanica1 + prvaStanica2[1:len(prvaStanica2)]
  644. print rez
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement