Question
For the programming portion of the assignment, please submit only your .java files and your README.txt. Your code should be well commented. In addition please
For the programming portion of the assignment, please submit only your .java files and your README.txt. Your code should be well commented. In addition please include a detailed README.txt file which indicates exactly what files you are submitting, what problem they solve, and how to compile and run them.
In this problem you will find solutions to the traveling salesman problem (TSP) and display the tours using the provided GUI. Download and unpack the file programming.zip, which contains the GUI and a graph implementation. The graph implementation is identical to the one used for Programming problem 2 on Homework 5, except that vertices are identified by Integers instead. Running the program Display will bring up a window with an empty canvas to display Graphs. Clicking "Generate Random Graph" does nothing and clicking either "Nearest Neighbor" or "Brute Force" will throw a null pointer exception on the terminal. You task is to implement these methods in Graph.java.
Generating a Random Complete Graph - in Graph.java, implement the method generateRandomVertices(int n). This method should add vertices and edges to the Graph instance. After running the method, the instance should represent a complete graph with n vertices with the IDsames 0,1,...,n-1 at random (x,y) coordinates. xand y can range between 0 and 100. Use java.util.Random (Links to an external site.)Links to an external site. to create random numbers. If the method is implemented correctly, clicking on "Generate Random Graph" in the GUI will display the graph.
Nearest Neighbor - Implement the method nearestNeighborTsp(), which should use the nearest neighbor algorithm to find an estimate of the shortest simple cycle that visits each vertex. The method should return a list of Edges on the cycle. Make sure to add the correct distance to each edge. If the method is implemented correctly, clicking on "Nearest Neighbor" in the GUI will display the nearest neighbor tour as an overlay. The GUI will also display the sum of edge costs, as well as the time required to compute the tour. This should not take longer than a few milliseconds for a graph of size 8.
Brute Force - Implement the method bruteForceTsp(), which should compute the actual shortest simple cycle visiting each vertex. The method returns this cycle in the same format as nearestNeighborTsp(). You can run the method by clicking the "Brute Force" button, but it is not advisable to try this for graphs with n>8. Hint: Because the graph is complete, the set of possible TSP cycles corresponds to all possible permutations of the vertices. In our graph representation, the vertices are identified by Integers. Try the following:
First, enumerate all possible permutations of the integers 0 to n-1. You should use additional methods to do this.
For each permutation, measure the total cost of the corresponding cycle (sum of edge costs).
Select the permutation with the lowest total cost.
In your README, compare and comment on the actual time required by the Nearest Neighbor method and the Brute Force method for random graphs with graphs from 2 to 8 vertices. Run the algorithms on at least 3 different graphs for each n and average the runtime results.
Point breakdown: 7 points for generating the random cities. 35 points for the brute force solution, and 28 points for the nearest neighbor solution.
import java.awt.BasicStroke; import java.awt.Color; import java.awt.Desktop; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.RenderingHints; import java.awt.Stroke; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import java.util.LinkedList; import java.util.List;
import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JSeparator; import javax.swing.JTextField; import javax.swing.UIManager; import javax.swing.border.EmptyBorder;
@SuppressWarnings("serial") public class Display extends JFrame {
private JPanel contentPane; private GraphPanel panel; private Graph graph; private JTextField textField;
/** * Launch the application. */ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { Display frame = new Display(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); }
public static Graph graphFactory() { Graph graph = new Graph(); return graph; }
/** * Create the frame. */ public Display() { setTitle("Data Structures Graph Visualizer"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(50, 50, 900, 700); setMinimumSize(new Dimension(800, 600)); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(10, 10, 10, 10)); setContentPane(contentPane); GridBagLayout gbl_contentPane = new GridBagLayout(); gbl_contentPane.columnWidths = new int[] { 0, 0, 0, 0 }; gbl_contentPane.rowHeights = new int[] { 0, 0, 0, 0, 0, 0, 0, 0 }; gbl_contentPane.columnWeights = new double[] { 0.0, 0.0, 1.0, Double.MIN_VALUE }; gbl_contentPane.rowWeights = new double[] { 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE }; contentPane.setLayout(gbl_contentPane);
graph = graphFactory();
panel = new GraphPanel(graph); GridBagConstraints gbc_panel = new GridBagConstraints(); gbc_panel.gridwidth = 7; gbc_panel.insets = new Insets(0, 0, 7, 0); gbc_panel.fill = GridBagConstraints.BOTH; gbc_panel.gridx = 0; gbc_panel.gridy = 0; contentPane.add(panel, gbc_panel);
JSeparator separator = new JSeparator(); separator.setBackground(Color.WHITE); separator.setForeground(Color.GRAY); GridBagConstraints gbc_separator = new GridBagConstraints(); gbc_separator.fill = GridBagConstraints.BOTH; gbc_separator.gridwidth = 4; gbc_separator.insets = new Insets(0, 0, 5, 0); gbc_separator.gridx = 0; gbc_separator.gridy = 1; contentPane.add(separator, gbc_separator);
JLabel lblPanda = new JLabel("Panda 2016
JLabel lblGenerateRandomGraph = new JLabel("Generate Random Graph"); GridBagConstraints gbc_lblGenerateRandomGraph = new GridBagConstraints(); gbc_lblGenerateRandomGraph.anchor = GridBagConstraints.EAST; gbc_lblGenerateRandomGraph.insets = new Insets(0, 0, 5, 5); gbc_lblGenerateRandomGraph.gridx = 0; gbc_lblGenerateRandomGraph.gridy = 2; contentPane.add(lblGenerateRandomGraph, gbc_lblGenerateRandomGraph);
textField = new JTextField(); textField.setText("5"); GridBagConstraints gbc_textField = new GridBagConstraints(); gbc_textField.insets = new Insets(0, 0, 5, 5); gbc_textField.fill = GridBagConstraints.HORIZONTAL; gbc_textField.gridx = 1; gbc_textField.gridy = 2; contentPane.add(textField, gbc_textField); textField.setColumns(10);
JButton btnGenerateRandomGraph = new JButton("Generate Random Graph");
GridBagConstraints gbc_btnGenerateRandomGraph = new GridBagConstraints(); gbc_btnGenerateRandomGraph.fill = GridBagConstraints.BOTH; gbc_btnGenerateRandomGraph.insets = new Insets(0, 0, 5, 0); gbc_btnGenerateRandomGraph.gridx = 3; gbc_btnGenerateRandomGraph.gridy = 2; contentPane.add(btnGenerateRandomGraph, gbc_btnGenerateRandomGraph);
JLabel lblNearestNeighbor = new JLabel("Nearest Neighbor"); GridBagConstraints gbc_lblNearestNeighbor = new GridBagConstraints(); gbc_lblNearestNeighbor.anchor = GridBagConstraints.EAST; gbc_lblNearestNeighbor.insets = new Insets(0, 0, 5, 5); gbc_lblNearestNeighbor.gridx = 0; gbc_lblNearestNeighbor.gridy = 3; contentPane.add(lblNearestNeighbor, gbc_lblNearestNeighbor);
JLabel lblNearestneighbordistance = new JLabel(""); GridBagConstraints gbc_lblNearestneighbordistance = new GridBagConstraints(); gbc_lblNearestneighbordistance.insets = new Insets(0, 0, 5, 5); gbc_lblNearestneighbordistance.gridx = 1; gbc_lblNearestneighbordistance.gridy = 3; contentPane.add(lblNearestneighbordistance, gbc_lblNearestneighbordistance); JLabel lblNearestneighbortime = new JLabel(""); GridBagConstraints gbc_lblNearestneighbortime = new GridBagConstraints(); gbc_lblNearestneighbortime.insets = new Insets(0, 0, 5, 5); gbc_lblNearestneighbortime.gridx = 2; gbc_lblNearestneighbortime.gridy = 3; contentPane.add(lblNearestneighbortime, gbc_lblNearestneighbortime);
JButton btnNearestNeighbor = new JButton("Nearest Neighbor"); btnNearestNeighbor.addMouseListener(new MouseAdapter() { @Override public void mouseReleased(MouseEvent e) { long startTime = System.nanoTime(); System.out.println("Running nearestNeighborTsp() to compute TSP tour."); List
JLabel lblBruteForce = new JLabel("Brute Force"); GridBagConstraints gbc_lblBruteForce = new GridBagConstraints(); gbc_lblBruteForce.anchor = GridBagConstraints.EAST; gbc_lblBruteForce.insets = new Insets(0, 0, 5, 5); gbc_lblBruteForce.gridx = 0; gbc_lblBruteForce.gridy = 4; contentPane.add(lblBruteForce, gbc_lblBruteForce);
JLabel lblBruteforcedistance = new JLabel(""); GridBagConstraints gbc_lblBruteforcedistance = new GridBagConstraints(); gbc_lblBruteforcedistance.insets = new Insets(0, 0, 5, 5); gbc_lblBruteforcedistance.gridx = 1; gbc_lblBruteforcedistance.gridy = 4; contentPane.add(lblBruteforcedistance, gbc_lblBruteforcedistance);
JLabel lblBruteforcetime = new JLabel(""); GridBagConstraints gbc_lblBruteforcetime = new GridBagConstraints(); gbc_lblBruteforcetime.insets = new Insets(0, 0, 5, 5); gbc_lblBruteforcetime.gridx = 2; gbc_lblBruteforcetime.gridy = 4; contentPane.add(lblBruteforcetime, gbc_lblBruteforcetime);
JButton btnBruteForce = new JButton("Brute Force"); btnBruteForce.addMouseListener(new MouseAdapter() { @Override public void mouseReleased(MouseEvent e) { long startTime = System.nanoTime(); System.out.println("Running bruteForceTsp() to compute optimal TSP tour."); List
JSeparator separator_1 = new JSeparator(); separator_1.setForeground(Color.GRAY); separator_1.setBackground(Color.WHITE); GridBagConstraints gbc_separator_1 = new GridBagConstraints(); gbc_separator_1.fill = GridBagConstraints.BOTH; gbc_separator_1.gridwidth = 4; gbc_separator_1.insets = new Insets(0, 0, 5, 0); gbc_separator_1.gridx = 0; gbc_separator_1.gridy = 5; contentPane.add(separator_1, gbc_separator_1); GridBagConstraints gbc_lblPanda = new GridBagConstraints(); gbc_lblPanda.gridwidth = 3; gbc_lblPanda.anchor = GridBagConstraints.EAST; gbc_lblPanda.gridx = 1; gbc_lblPanda.gridy = 6; contentPane.add(lblPanda, gbc_lblPanda);
btnGenerateRandomGraph.addMouseListener(new MouseAdapter() { @Override public void mouseReleased(MouseEvent e) { int n = 5; try { n = Integer.valueOf(textField.getText()); } catch (NumberFormatException exception) { textField.setText("5"); repaint(); } if (n > 8) { Object[] options = { "Shut up Linan", "I'll change it" }; int m = JOptionPane.showOptionDialog(panel, "You are about to generate " + n + " vertices. Drawing this may slow down your computer. Running brute force algorithms on a graph " + "" + "larger than 8 vertices will probably take forever. Your computer may flip out on strike." + " Are you sure you want to do this?", "Don't be cruel to your computer", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[1]); if (m == 1) { textField.setText("5"); repaint(); return; } }
System.out.println("Resetting brute force and nearest neighbor paths"); panel.overlayEdges = new HashMap(); System.out.println("Calling generateRandomVertices(" + n + ")"); panel.graph.generateRandomVertices(n); lblBruteforcedistance.setText(""); lblNearestneighbordistance.setText("");
panel.repaint(); } });
updateGraphPanel(); }
private void updateGraphPanel() { graph = graphFactory(); panel.graph = graph;
panel.overlayEdges.put("brute", new LinkedList
repaint(); }
public class GraphPanel extends JPanel {
// graph layout parameters public static final int VERTEX_RADIUS = 10; public static final int SPACE = 3;
public static final int MARGIN_X = 50; public static final int MARGIN_Y = 50;
public static final int DEFAULT_THICKNESS = 1;
// scale factors public float xFactor, yFactor;
public Graph graph;
public HashMap
public GraphPanel(Graph graph) { this.graph = graph; overlayEdges = new HashMap(); overlayEdges.put("brute", new LinkedList
public void paintComponent(Graphics g) { // make everything smooth like butter Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); g2.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); g2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
// scale the graph int minX = 0; int maxX = 1; int minY = 0; int maxY = 1; for (Vertex v : graph.getVertices()) { if (v.x maxX) maxX = v.x; if (v.y maxY) maxY = v.y; } xFactor = (this.getBounds().width - 2 * MARGIN_X) / (float) (maxX - minX); yFactor = (this.getBounds().height - 2 * MARGIN_Y) / (float) (maxY - minY); super.paintComponent(g2); // paint the panel paintGraph(g2); // paint the graph }
public void paintGraph(Graphics g) { for (Vertex v : graph.getVertices()) { for (Edge edge : v.adjacentEdges) { paintEdge(g, edge.source, edge.target, edge.distance, Color.LIGHT_GRAY, DEFAULT_THICKNESS, 255); } } for (Vertex v : graph.getVertices()) { paintVertex(g, v); } for (String overlayType : overlayEdges.keySet()) { if (overlayType.equals("brute")) { for (Edge edge : overlayEdges.get(overlayType)) { paintEdge(g, edge.source, edge.target, edge.distance, Color.RED, 8, 50); } } if (overlayType.equals("nearest")) { for (Edge edge : overlayEdges.get(overlayType)) { paintEdge(g, edge.source, edge.target, edge.distance, Color.GREEN, 8, 50); } } } }
public void paintVertex(Graphics g, Vertex v) { Graphics2D g2 = (Graphics2D) g;
int x = Math.round(xFactor * (float) v.x + (float) MARGIN_X); int y = Math.round(yFactor * (float) v.y + (float) MARGIN_Y); g2.setColor(Color.LIGHT_GRAY); Stroke oldStroke = g2.getStroke(); g2.setStroke(new BasicStroke(4)); g2.drawOval(x - VERTEX_RADIUS / 2, y - VERTEX_RADIUS / 2, VERTEX_RADIUS, VERTEX_RADIUS); g2.setStroke(oldStroke); g2.setColor(Color.LIGHT_GRAY); g2.fillOval(x - VERTEX_RADIUS / 2, y - VERTEX_RADIUS / 2, VERTEX_RADIUS, VERTEX_RADIUS); g2.setColor(Color.DARK_GRAY); g2.drawString(Integer.toString(v.name), x - VERTEX_RADIUS / 2, y + VERTEX_RADIUS / 2); }
public void paintEdge(Graphics g, Vertex u, Vertex v, double weight, Color color, int thickness, int alpha) { Graphics2D g2 = (Graphics2D) g; int x1 = Math.round(xFactor * (float) u.x + (float) MARGIN_X); int y1 = Math.round(yFactor * (float) u.y + (float) MARGIN_Y); int x2 = Math.round(xFactor * (float) v.x + (float) MARGIN_X); int y2 = Math.round(yFactor * (float) v.y + (float) MARGIN_Y); g2.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha)); Stroke oldStroke = g2.getStroke(); g2.setStroke(new BasicStroke(thickness)); g2.drawLine(x1, y1, x2, y2); g2.setStroke(oldStroke); Font oldFont = g2.getFont(); g2.setFont(new Font("Helvetica", Font.PLAIN, 8)); g2.setColor(Color.GRAY); g2.drawString(String.format("%.1f", weight), (x1 + x2) / 2, (y1 + y2) / 2); g2.setFont(oldFont); } } }
public class Edge {
public double distance; public Vertex source; public Vertex target;
public Edge(Vertex vertex1, Vertex vertex2, double weight) { source = vertex1; target = vertex2; this.distance = weight; }
public String toString() { return source + " - " + target; } }
import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedList; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Random; import java.util.stream.Collectors;
public class Graph {
// Keep a fast index to nodes in the map private Map
/** * Construct an empty Graph with a map. The map's key is the name of a vertex * and the map's value is the vertex object. */ public Graph() { vertexNames = new HashMap(); }
/** * Adds a vertex to the graph. Throws IllegalArgumentException if two vertices * with the same name are added. * * @param v * (Vertex) vertex to be added to the graph */ public void addVertex(Vertex v) { if (vertexNames.containsKey(v.name)) throw new IllegalArgumentException("Cannot create new vertex with existing name."); vertexNames.put(v.name, v); }
/** * Gets a collection of all the vertices in the graph * * @return (Collection
/** * Gets the vertex object with the given name * * @param name * (String) name of the vertex object requested * @return (Vertex) vertex object associated with the name */ public Vertex getVertex(String name) { return vertexNames.get(name); }
/** * Adds a directed edge from vertex u to vertex v * * @param nameU * (String) name of vertex u * @param nameV * (String) name of vertex v * @param cost * (double) cost of the edge between vertex u and v */ public void addEdge(int nameU, int nameV, Double cost) { if (!vertexNames.containsKey(nameU)) throw new IllegalArgumentException(nameU + " does not exist. Cannot create edge."); if (!vertexNames.containsKey(nameV)) throw new IllegalArgumentException(nameV + " does not exist. Cannot create edge."); Vertex sourceVertex = vertexNames.get(nameU); Vertex targetVertex = vertexNames.get(nameV); Edge newEdge = new Edge(sourceVertex, targetVertex, cost); sourceVertex.addEdge(newEdge); }
/** * Adds an undirected edge between vertex u and vertex v by adding a directed * edge from u to v, then a directed edge from v to u * * @param name * (String) name of vertex u * @param name2 * (String) name of vertex v * @param cost * (double) cost of the edge between vertex u and v */ public void addUndirectedEdge(int name, int name2, double cost) { addEdge(name, name2, cost); addEdge(name2, name, cost); }
/** * Computes the euclidean distance between two points as described by their * coordinates * * @param ux * (double) x coordinate of point u * @param uy * (double) y coordinate of point u * @param vx * (double) x coordinate of point v * @param vy * (double) y coordinate of point v * @return (double) distance between the two points */ public double computeEuclideanDistance(double ux, double uy, double vx, double vy) { return Math.sqrt(Math.pow(ux - vx, 2) + Math.pow(uy - vy, 2)); }
/** * Computes euclidean distance between two vertices as described by their * coordinates * * @param u * (Vertex) vertex u * @param v * (Vertex) vertex v * @return (double) distance between two vertices */ public double computeEuclideanDistance(Vertex u, Vertex v) { return computeEuclideanDistance(u.x, u.y, v.x, v.y); }
/** * Calculates the euclidean distance for all edges in the map using the * computeEuclideanCost method. */ public void computeAllEuclideanDistances() { for (Vertex u : getVertices()) for (Edge uv : u.adjacentEdges) { Vertex v = uv.target; uv.distance = computeEuclideanDistance(u.x, u.y, v.x, v.y); } }
// STUDENT CODE STARTS HERE
public void generateRandomVertices(int n) { vertexNames = new HashMap(); // reset the vertex hashmap // Your code here... computeAllEuclideanDistances(); // compute distances }
public List
public List
// STUDENT CODE ENDS HERE
/** * Prints out the adjacency list of the graph for debugging */ public void printAdjacencyList() { for (int u : vertexNames.keySet()) { StringBuilder sb = new StringBuilder(); sb.append(u); sb.append(" -> [ "); for (Edge e : vertexNames.get(u).adjacentEdges) { sb.append(e.target.name); sb.append("("); sb.append(e.distance); sb.append(") "); } sb.append("]"); System.out.println(sb.toString()); } } }
import java.util.LinkedList; import java.util.List;
public class Vertex {
public int name; public int x; public int y; public boolean known; public double distance; // total distance from origin point public Vertex prev; public List
public Vertex(int name, int x, int y) { this.name = name; this.x = x; this.y = y; // by default java sets uninitialized boolean to false and double to 0 // hence known == false and dist == 0.0 adjacentEdges = new LinkedList
@Override public int hashCode() { // we assume that each vertex has a unique name return name; }
@Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null) { return false; } if (!(o instanceof Vertex)) { return false; } Vertex oVertex = (Vertex) o;
return name == oVertex.name && x == oVertex.x && y == oVertex.y; }
public void addEdge(Edge edge) { adjacentEdges.add(edge); }
public String toString() { return name + " (" + x + ", " + y + ")"; }
}
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started