Suppose there are a number of "cities," as in Figure 1 below. The distance between any two cities is the standard Euclidian distance, that is, √((x1-x2)2+(y1-y2)2). There are two problems to be solved.
![]() |
![]() |
![]() |
| Figure 1, Cities. | Figure 2. A circuit. | Figure 3. A spanning tree. |
A travelling salesman wishes to visit every city exactly once, then return to his starting point. (It doesn't matter what city is the starting point.) Such a path is called a circuit, as in Figure 2. However, the salesman also wishes to minimize the total distance that must be travelled.
A telegraph company wishes to put telegraph lines between cities, such that every city is connected (however indirectly) to every other city, with no circuits. Such a set of connections is called a spanning tree, as in Figure 3. To keep costs down, the company wishes to minimize the total distance that it must put wires.
(If you don't like telegraphs, call it electric power lines, or road building, or fiber optic cables.)
These are classic computer science problems, known as the Travelling Salesman problem and the Minimum Spanning Tree problem. You can find algorithms for solving them on the web, and you are welcome to look at those algorithms. However, I want you use a hill climbing approach, where you start with "any" solution, and try to progressively improve it until you can't improve it any more.
This should require you to think about how to solve the problem, rather than just copying some algorithm you may or may not understand. Your final solution is unlikely to be the optimal (best possible) solution, but that's okay, so long as it isn't obviously terrible.
There will be from 1 to 26 cities, with names "a", "b", "c", etc. Each city will have an x-y location, which is a 2-tuple of floating point numbers, such as (743.02, 215.53), where each number is between 0.0 and 1000.0. When I use the term directory in the function descriptions below, it will refer to a dictionary whose keys are city names and whose values are the corresponding x-y locations.
To represent either a circuit or a spanning tree, use a dictionary whose keys are city names, and whose values are a set of the names of the directly connected cities. In the function descriptions below, I will call this kind of dictionary a road_map. For a circuit, each set will contain exactly two city names; for a spanning tree, each set will contain one or more city names.
While I will require these particular data representations as function parameters and function results, this does not imply that you have to work with these representations as you solve the problems. Python makes it easy to convert from one kind of sequence to another.
cities.py)def create_cities(how_many)directory.def print_cities(directory)def create_cycle(directory)road_map that describes an initial (probably not very good) cycle.def create_spanning_tree(directory)road_map that describes an initial (probably not very good) spanning tree.def compute_cost(road_map, directory)road_map.def improve_cycle(road_map, directory)road_map to be slightly better (have a lower cost) and returns True if it succeeds, False if no further improvement can be found. This may involve trying many small changes, until one is found that reduces the total cost of the cycle. It is your job to figure out how to do this. (You do not have to return the road_map; since it is an object, any changes you make will be seen in the calling function.)def improve_spanning_tree(road_map, directory)road_map to be slightly better (have a lower cost) and returns True if it succeeds, False if no further improvement can be found. This may involve trying many small changes, until one is found that reduces the total cost of the spanning tree. It is your job to figure out how to do this. (You do not have to return the road_map; since it is an object, any changes you make will be seen in the calling function.)def find_best_cycle(road_map, directory)road_map until you can find no further improvements. This does not need to be the best possible solution; it only needs to be "reasonably good." (You do not have to return the road_map; since it is an object, any changes you make will be seen in the calling function.)def find_best_spanning_tree(road_map, directory)road_map until you can find no further improvements. This does not need to be the best possible solution; it only needs to be "reasonably good." (You do not have to return the road_map; since it is an object, any changes you make will be seen in the calling function.)def print_map(road_map, directory)def main()cities_test.py)All functions, except the main, print_cities, and print_map, should be tested. This includes any additional functions you might write.
TDD, Test Driven Design, really is a good idea. Here is the general approach:
Put both names (yours and your partner's) in a comment at the top of both files. You may, if you wish, put your name in a comment in the major functions you have written; but you will both get the same grade for the assignment.
This assignment has been written to have a common part, and two easily separable problems. You should work with your partner as much as possible; but if you must work apart, one of you should work on the travelling salesman problem, and the other should work on the spanning tree problem.
In the past, some students have tried the following: One partner writes the functions, and the other partner writes the test. Those students have told me, in no uncertain terms, that this is a bad idea. Learn from their mistakes. Whoever writes a function should also write the tests for that function.
random at the top of your program; then number = 1000 * random.random() will give you a floating-point number in the range 0.0 <= number < 1000.0.% operator (check your textbook) is a good way to print out floating-point numbers, for example, with the format %6.2f.ord('a') is 97; chr(97) is 'a'; and similarly for other letters.The assignment will be graded on the basis of 100 points total. You and your partner will receive the same grade. Grading will be based on:
if better == True). .rar) your .py files and submit the zipped file to Canvas. No other form of submission will be accepted.