diff --git a/Submissions/002734572_Douhao_Ma/Assignment1.readme b/Submissions/002734572_Douhao_Ma/Assignment1/Assignment1.readme similarity index 100% rename from Submissions/002734572_Douhao_Ma/Assignment1.readme rename to Submissions/002734572_Douhao_Ma/Assignment1/Assignment1.readme diff --git a/Submissions/002734572_Douhao_Ma/assignment1.ipynb b/Submissions/002734572_Douhao_Ma/Assignment1/assignment1.ipynb similarity index 100% rename from Submissions/002734572_Douhao_Ma/assignment1.ipynb rename to Submissions/002734572_Douhao_Ma/Assignment1/assignment1.ipynb diff --git a/Submissions/002734572_Douhao_Ma/pic.png b/Submissions/002734572_Douhao_Ma/Assignment1/pic.png similarity index 100% rename from Submissions/002734572_Douhao_Ma/pic.png rename to Submissions/002734572_Douhao_Ma/Assignment1/pic.png diff --git a/Submissions/002734572_Douhao_Ma/Assignment2/1A.jpg b/Submissions/002734572_Douhao_Ma/Assignment2/1A.jpg new file mode 100644 index 0000000..88627e1 Binary files /dev/null and b/Submissions/002734572_Douhao_Ma/Assignment2/1A.jpg differ diff --git a/Submissions/002734572_Douhao_Ma/Assignment2/as2.ipynb b/Submissions/002734572_Douhao_Ma/Assignment2/as2.ipynb new file mode 100644 index 0000000..5c9fe94 --- /dev/null +++ b/Submissions/002734572_Douhao_Ma/Assignment2/as2.ipynb @@ -0,0 +1,594 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "83668f8f-9515-46e3-95b3-f3d5a0d2ee1e", + "metadata": {}, + "source": [ + "# Assignment 2" + ] + }, + { + "cell_type": "markdown", + "id": "31bc715c-011f-47db-8b9e-dc3788894d64", + "metadata": {}, + "source": [ + "Q1 \n", + "Use Kruskal's algorithm to find a minimum spanning tree for the connected weighted graph below:" + ] + }, + { + "cell_type": "markdown", + "id": "29416c63-1b92-45df-a180-12ea371138ae", + "metadata": {}, + "source": [ + "![pic](pic1.jpg)\n" + ] + }, + { + "cell_type": "raw", + "id": "2b38aaff-3ec6-4370-882a-d72b5eaee2d3", + "metadata": {}, + "source": [ + "Solution: \n", + "Kruskal's algorithm pseudocode: \n", + "Kruskal(G):\r\n", + " 1. Initialize an empty minimum spanning tree (MST).\r\n", + " 2. Sort all the edges in graph G in ascending order of their weights.\r\n", + " 3. Initialize an empty disjoint-set data structure to track the connectivity of nodes.\r\n", + " 4. For each edge (u, v) in the sorted order:\r\n", + " a. If the edge (u, v) does not form a cycle (i.e., u and v are not in the same connected component):\r\n", + " i. Add the edge (u, v) to MST.\r\n", + " ii. Merge the connected components containing u and v.\r\n", + " rn MST.\n", + "Steps:\n", + "1. connect A-C(1)\n", + "2. connect C-D(1)\n", + "3. connect A-B(2)\n", + "4. connect C-F(2)\n", + "5. connect D-E(2)\n", + "6. MST formed, (5 edges 6 vertices)formed.\r\n" + ] + }, + { + "cell_type": "markdown", + "id": "2692ceff-a98e-43c1-ac75-cee696e4235f", + "metadata": {}, + "source": [ + "![pic](1A.jpg)" + ] + }, + { + "cell_type": "raw", + "id": "e958b800-df8d-42e9-99ba-93b3f8040773", + "metadata": {}, + "source": [ + "Kruskal's algorithm is O(E log V) time. Where E is the set of edges and V is the set of vertices" + ] + }, + { + "cell_type": "markdown", + "id": "b022be1a-c3ab-46fc-a2fe-9ef498cf9fe4", + "metadata": {}, + "source": [ + "Q2 \n", + "Use Prim's algorithm to find a minimum spanning tree for the connected weighted graph below:" + ] + }, + { + "cell_type": "markdown", + "id": "dd504ab4-ee45-44c2-8e7f-ab3bd9b294cc", + "metadata": {}, + "source": [ + "![pic](pic1.jpg)" + ] + }, + { + "cell_type": "raw", + "id": "ee444c90-3297-4a9d-8eb4-ee65a7c76cac", + "metadata": {}, + "source": [ + "Solution: \n", + "Prim's algorithm pseudocode: \n", + "Prim(G, start_vertex):\n", + " 1. Initialize an empty minimum spanning tree MST.\n", + " 2. Initialize a priority queue (or a min-heap) Q to store candidate edges.\n", + " 3. Add start_vertex to MST.\n", + " 4. Add all edges (u, v) from start_vertex to its neighbors to Q.\n", + " 5. While the number of nodes in MST is less than the total number of nodes in G, repeat:\n", + " a. Remove the edge (u, v) with the smallest weight from Q.\n", + " b. If vertex v is not in MST:\n", + " i. Add edge (u, v) to MST.\n", + " ii. Add all edges (v, w) from vertex v to its unvisited neighbors w to Q.\n", + " 6. Return MST.\n", + "\n", + "Steps:\n", + "1. Select A, MST={A}, Q={B,C,D,E,F}\n", + "2. A-C has the shortest path, so select C, connect A-C, MST={A,C}, Q={B,D,E,F}\n", + "3. C-D has the shortest path, so select D, connect C-D, MST={A,C,D}, Q={B,E,F}\n", + "4. D-E has the shortest path, so select E, connect D-E, MST={A,C,D,E}, Q={B,E}\n", + "5. C-F has the shortest path, so select F, connect C-F, MST={A,C,D,E,F}, Q={B}\n", + "5. A-B has the shortest path, so select B, connect A-B, MST={A,C,D,E,F,B}, Q={}\n", + "7. Done, return MST" + ] + }, + { + "cell_type": "markdown", + "id": "d4593432-f638-4883-9b1d-4b7ab325547b", + "metadata": {}, + "source": [ + "![pic](1A.jpg)" + ] + }, + { + "cell_type": "raw", + "id": "ed6c2447-9c5b-48e7-b775-9c1e8eed18ec", + "metadata": {}, + "source": [ + "When using simple data structure, the Prim's algorithm is O(V^2) time, where V is the number of vertices" + ] + }, + { + "cell_type": "markdown", + "id": "5c42a6ed-2708-4bea-b145-665f25fcd862", + "metadata": {}, + "source": [ + "Q3 \n", + "Given the DAG below, determine whether it can be topological sorted or not, give the pseudocode of topological sorted" + ] + }, + { + "cell_type": "markdown", + "id": "a10f1d90-3eb6-46d7-a54f-e07ca51181f4", + "metadata": {}, + "source": [ + "![pic](pic2.jpg)" + ] + }, + { + "cell_type": "raw", + "id": "b70e21b3-a961-4f0f-b0e7-23524f0b931d", + "metadata": {}, + "source": [ + "Solution:\n", + "Yes, it can be topologically sorted, pseudocode:\n", + "TopologicalSort(G):\n", + " 1. Initialize an empty array result to store the topological ordering.\n", + " 2. Create an empty queue or stack called queue to store nodes with in-degree 0.\n", + " 3. Calculate the in-degree of each node and add nodes with in-degree 0 to the queue.\n", + " 4. Enter the main loop until the queue is empty:\n", + " a. Dequeue a node u from the queue.\n", + " b. Add node u to the result.\n", + " c. Iterate through all neighboring nodes v of node u:\n", + " i. Decrease the in-degree of node v.\n", + " ii. If the in-degree of node v becomes 0, enqueue node v.\n", + " 5. If the number of nodes in the result is equal to the number of nodes in graph G, the topological sort is successful, and return the result.\n", + " 6. Otherwise, there is a cycle in graph G, and topological sorting is not possible.\n", + "\n", + "Steps:\n", + "L= {}\n", + "Remove A (no incoming edges) L= {A}\n", + "Remove B (no incoming edges) L= {A, B}\n", + "Remove C (no incoming edges) L= {A, B, C}\n", + "Remove D (no incoming edges) L= {A, B, C, D}\n", + "Remove E (no incoming edges) L= {A, B, C, D, E,}\n", + "Remove F (no incoming edges) L= {A, B, C, D, E, F}\n", + "Done" + ] + }, + { + "cell_type": "markdown", + "id": "29bb2784-b127-47bc-9c10-6bcbe3a539cd", + "metadata": {}, + "source": [ + "Q4 \n", + "For each of the following recurrences, give an expression for the runtime T(n) if the recurrence can be \n", + "solved with the Master Theorem. Otherwise, indicate that the Master Theorem does not apply" + ] + }, + { + "cell_type": "raw", + "id": "b722512e-0297-49ab-8579-08f945eb092c", + "metadata": {}, + "source": [ + "i. T(n) = 4T(n/2) + n^2\n", + "ii. T(n) = 5T(n/3) + n^3\n", + "iii. T(n) = 2T(n/4) + n\n", + "iv. T(n) = 3nT(n/3) + n^2.5\n", + "v. T(n) = n^2T(n/2) + n^1.5" + ] + }, + { + "cell_type": "raw", + "id": "c1b490b0-e5ac-4ca2-9b14-5ae34a06678f", + "metadata": {}, + "source": [ + "Solution: \n", + "i. T(n) = 4T(n/2) + n^2\n", + "a = 4, b = 2, and f(n) = n^2\n", + "Here, a = b^c, where c = 2. So, it falls into Case 2 of the Master Theorem.\n", + "T(n) = Θ(n^c * log n) = Θ(n^2 * log n)\n", + "\n", + "ii. T(n) = 5T(n/3) + n^3\n", + "a = 5, b = 3, and f(n) = n^3\n", + "Here, a > b^c, where c = 3. So, it falls into Case 1 of the Master Theorem.\n", + "T(n) = Θ(n^c) = Θ(n^3)\n", + "\n", + "iii. T(n) = 2T(n/4) + n\n", + "a = 2, b = 4, and f(n) = n\n", + "Here, a < b^c for any positive c. So, it falls into Case 1 of the Master Theorem.\n", + "T(n) = Θ(n^c) = Θ(1)\n", + "\n", + "iv. T(n) = 3nT(n/3) + n^2.5\n", + "Master Theorem does not apply A is a function of n.\n", + "\n", + "v. T(n) = n^2T(n/2) + n^1.5\n", + "Master Theorem does not apply A is a function of n." + ] + }, + { + "cell_type": "markdown", + "id": "d4718bf8-46b2-44e5-886c-4269c4e391bb", + "metadata": {}, + "source": [ + "Q5 \n", + "Given the following graph, use the Dijkstra algorithm to find the shortest paths from point A to all other points, and show your steps." + ] + }, + { + "cell_type": "markdown", + "id": "be81a73a-3448-4500-9316-8a0f5f24a7dd", + "metadata": {}, + "source": [ + "![pic](pic5.jpg)" + ] + }, + { + "cell_type": "raw", + "id": "d8220d13-19af-4ed1-8fec-7aaa0f95728a", + "metadata": {}, + "source": [ + "Solution:\n", + "Pseudocode:\n", + "\n", + "Step 1: Initialization\n", + "Create an empty set of the shortest paths called S.\n", + "Create a distance table to record distances from A to all points. Initially, set the distance from A to itself to 0, and set the distances to all other points to infinity.\n", + "Create a priority queue (or a min-heap) called Q and add all nodes to it.\n", + "\n", + "Step 2: Starting from A\n", + "Select the node X with the smallest distance from A in the queue Q.\n", + "Remove node X from the queue Q and add it to the set S.\n", + "\n", + "Step 3: Update the Distance Table\n", + "For all unvisited neighbor nodes Y of node X, calculate the distance from A to Y through X (i.e., the distance from A to X plus the weight of the edge from X to Y). If this distance is smaller than the recorded distance to node Y in the distance table, update the distance value for Y in the distance table.\n", + "Repeat Step 2 and Step 3 until the queue Q is empty.\n", + "\n", + "Step 4: Shortest Paths\n", + "In the end, the distance table records the distances from A to all other points, representing the shortest paths.\n", + "These steps will help you use the Dijkstra algorithm to find the shortest paths from point A to all other points and illustrate the detailed operations at each step." + ] + }, + { + "cell_type": "markdown", + "id": "f3875b00-0cf1-48e9-99f6-db69019dbfb3", + "metadata": {}, + "source": [ + "| Vertex | Known | Cost | Previous |\r\n", + "|--------|-------|-------|----------|\r\n", + "| A | F | 0 | |\r\n", + "| B | F | -INF | \n", + "| C | F | INF | |\n", + "| D | F | INF | |\n", + "| E | F | INF | |\n", + "| F | F | INF | | | | |\r\n" + ] + }, + { + "cell_type": "raw", + "id": "895b02c7-591d-4a02-b9d8-1af190bdb567", + "metadata": {}, + "source": [ + "Update neighbor of A:" + ] + }, + { + "cell_type": "markdown", + "id": "cbdd5695-adcc-4cc7-942f-3e51ce434f4e", + "metadata": {}, + "source": [ + "| Vertex | Known | Cost | Previous |\n", + "|--------|-------|-------|----------|\n", + "| A | T | 0 | |\n", + "| B | F | 2 | A |\n", + "| C | F | 7 | A |\n", + "| D | F | INF | |\n", + "| E | F | INF | |\n", + "| F | F | 8 | A |" + ] + }, + { + "cell_type": "raw", + "id": "4b041b0e-8d1d-4f84-92e1-d45f606008c9", + "metadata": {}, + "source": [ + "Select minimum cost from unknown vertex, B, mark as known, and update ist nerghbor" + ] + }, + { + "cell_type": "markdown", + "id": "13896089-d299-4329-ae13-c3bc09a61b4c", + "metadata": {}, + "source": [ + "| Vertex | Known | Cost | Previous |\n", + "|--------|-------|-------|----------|\n", + "| A | T | 0 | |\n", + "| B | T | 2 | A |\n", + "| C | F | 5 | B |\n", + "| D | F | 6 | B |\n", + "| E | F | INF | |\n", + "| F | F | 8 | A |" + ] + }, + { + "cell_type": "raw", + "id": "68f98f42-ba34-4ead-9f8f-905774c9faff", + "metadata": {}, + "source": [ + "Select minimum cost from unknown vertex, C, mark as known, and update ist nerghbor" + ] + }, + { + "cell_type": "markdown", + "id": "a0d88625-5f0d-4f04-999a-205a9f397e1c", + "metadata": {}, + "source": [ + "| Vertex | Known | Cost | Previous |\n", + "|--------|-------|-------|----------|\n", + "| A | T | 0 | |\n", + "| B | T | 2 | A |\n", + "| C | T | 5 | B |\n", + "| D | F | 6 | B |\n", + "| E | F | 7 | C |\n", + "| F | F | 8 | A |" + ] + }, + { + "cell_type": "raw", + "id": "df37f709-b303-49c1-9779-d32d0b798890", + "metadata": {}, + "source": [ + "Select minimum cost from unknown vertex, D, mark as known, and update ist nerghbor(none of them would be updated)" + ] + }, + { + "cell_type": "markdown", + "id": "0d3563de-35f4-447f-80a6-cefb22a51001", + "metadata": {}, + "source": [ + "| Vertex | Known | Cost | Previous |\n", + "|--------|-------|-------|----------|\n", + "| A | T | 0 | |\n", + "| B | T | 2 | A |\n", + "| C | T | 5 | B |\n", + "| D | T | 6 | B |\n", + "| E | F | 7 | C |\n", + "| F | F | 8 | A |" + ] + }, + { + "cell_type": "raw", + "id": "693244c3-4104-4341-a988-321504e08077", + "metadata": {}, + "source": [ + "Select minimum cost from unknown vertex, E, mark as known, and update ist nerghbor(none of them would be updated)" + ] + }, + { + "cell_type": "markdown", + "id": "3533996c-f0e7-4eba-acca-4dac12beb4f0", + "metadata": {}, + "source": [ + "| Vertex | Known | Cost | Previous |\n", + "|--------|-------|-------|----------|\n", + "| A | T | 0 | |\n", + "| B | T | 2 | A |\n", + "| C | T | 5 | B |\n", + "| D | T | 6 | B |\n", + "| E | T | 7 | C |\n", + "| F | T | 8 | A |" + ] + }, + { + "cell_type": "raw", + "id": "c1adb3e7-f7d3-444f-a4a0-1b3585999bfe", + "metadata": {}, + "source": [ + "Select minimum cost from unknown vertex, F, mark as known, and update ist nerghbor(none of them would be updated)\n", + "Done, the shortest path from A to E is A-B-C-E" + ] + }, + { + "cell_type": "markdown", + "id": "15109414-4f55-45f3-85d7-5e70c3bf0c8d", + "metadata": {}, + "source": [ + "Q6 \n", + "You have a knapsack with a capacity of W, and you have 6 items with their respective weights and values as follows:\n", + "\n", + "- Item 1: Weight 2, Value 5\n", + "- Item 2: Weight 3, Value 7\n", + "- Item 3: Weight 1, Value 2\n", + "- Item 4: Weight 4, Value 9\n", + "- Item 5: Weight 5, Value 10\n", + "- Item 6: Weight 2, Value 4\n", + "\n", + "Your task is to choose which items to put into the knapsack, such that the total weight does not exceed the knapsack's capacity W, and the total value of the items is maximized.\n", + "What items should you choose to maximize the total value, and what is the maximum total value you can achieve?" + ] + }, + { + "cell_type": "raw", + "id": "a2e32064-814e-462b-bfac-7705909b1d95", + "metadata": {}, + "source": [ + "Solution:\n", + "Pseudocode: \n", + "Initialize a 2D array dp[n+1][W+1] with zeros\n", + "for i from 1 to n:\n", + " for j from 1 to W:\n", + " if weights[i-1] > j:\n", + " dp[i][j] = dp[i-1][j]\n", + " else:\n", + " dp[i][j] = max(dp[i-1][j], dp[i-1][j-weights[i-1]] + values[i-1])\n", + "\n", + "Initialize an empty list selected_items\n", + "i = n\n", + "j = W\n", + "while i > 0 and j > 0:\n", + " if dp[i][j] != dp[i-1][j]:\n", + " Add i to selected_items\n", + " j = j - weights[i-1]\n", + " Decrement i by 1" + ] + }, + { + "cell_type": "markdown", + "id": "369fded7-6bae-4903-84e5-f985b37317c4", + "metadata": {}, + "source": [ + "| Item\\Capacity | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |\n", + "|---------------|----|----|----|----|----|----|----|----|\n", + "| Item 1 | 0 | 0 | 5 | 5 | 10 | 10 | 15 | 15 |\n", + "| Item 2 | 0 | 0 | 5 | 7 | 10 | 12 | 15 | 17 |\n", + "| Item 3 | 0 | 2 | 5 | 7 | 10 | 12 | 15 | 17 |\n", + "| Item 4 | 0 | 2 | 5 | 7 | 9 | 12 | 14 | 17 |\n", + "| Item 5 | 0 | 2 | 5 | 7 | 9 | 10 | 12 | 14 |\n", + "| Item 6 | 0 | 2 | 4 | 7 | 9 | 10 | 11 | 14 |" + ] + }, + { + "cell_type": "raw", + "id": "a3327e05-d73b-47e9-a03c-f12e8386474c", + "metadata": {}, + "source": [ + "Each element in the table represents the maximum total value that can be obtained with the given capacity when selecting the corresponding items. By filling out the table, we can observe that when the knapsack capacity is 7, selecting items 1, 2, and 4 yields the maximum total value of 17.\n", + "\n", + "Therefore, when the knapsack capacity is 7, the optimal choice is items 1, 2, and 4, resulting in a total value of 17." + ] + }, + { + "cell_type": "markdown", + "id": "256c1b47-5bdd-4b28-9a5d-e42658e7e2c4", + "metadata": {}, + "source": [ + "Q7 \n", + "Prove that in any binary tree, the sum of depths of nodes with two children is equal to the sum of depths of leaf nodes." + ] + }, + { + "cell_type": "raw", + "id": "847c7a52-0e10-496a-a7dd-fa99a7c3bb64", + "metadata": {}, + "source": [ + "Solution:\n", + "Base Case: For a single-node binary tree (root only), the depth sum for the node with two children (the root) equals the depth sum for the leaf node (the root), which is 1.\n", + "\n", + "Inductive Hypothesis: Assume the statement holds for a binary tree with k nodes.\n", + "\n", + "Inductive Step: Prove that for a binary tree with k+1 nodes, the sum of depths of nodes with two children equals the sum of depths of leaf nodes.\n", + "\n", + "In a tree with k+1 nodes, we can add nodes in two ways:\n", + "\n", + "1. Adding a leaf node as a child to a node with one child (no change in depth sum).\n", + "2. Adding a node with two children as a child to a leaf node (increase depth sum by 1 for both).\n", + "Considering a tree with k nodes in both cases, according to the inductive hypothesis:\n", + "\n", + "Depth sum for nodes with two children = Depth sum for leaf nodes\n", + "Now, after considering both cases for a tree with k+1 nodes:\n", + "Depth sum for nodes with two children = Depth sum for leaf nodes\n", + "Therefore, in any binary tree, the sum of depths of nodes with two children equals the sum of depths of leaf nodes. This proof holds for all binary trees by induction." + ] + }, + { + "cell_type": "markdown", + "id": "3a7c5d6b-a283-4ad1-80c3-1f53934649fd", + "metadata": {}, + "source": [ + "Q8 \n", + "There's a book in which each page contains the content of the previous page plus some new sentences. The length of sentences on each page is limited to a constant 'c,' and the entire book contains 'n' words in total. Explain how to encode this book to minimize the encoding length 'f(n)' while ensuring that 'f(n)' grows as slowly as possible." + ] + }, + { + "cell_type": "raw", + "id": "377d8712-c451-461c-80f5-15329eb8c12a", + "metadata": {}, + "source": [ + "Solution:\n", + "This book can be encoded using a recursive or iterative approach where only the new sentences on each page need to be written, without the need to repeat the content from previous pages.\n", + "\n", + "For the first page, you need to write all the sentences on that page, which will require an encoding length of 'c.'\n", + "\n", + "For the second page, you only need to write the newly added sentences without repeating the content from the first page. This will also require an encoding length of 'c' because the length of sentences on each page is limited to 'c.'\n", + "\n", + "For subsequent pages, you similarly only need to write the newly added sentences without repeating the previous content. This will continue to require an encoding length of 'c.'\n", + "\n", + "Therefore, the total encoding length 'f(n)' will be proportional to the total word count 'n' in the book, without exhibiting faster growth. This helps minimize the encoding length while preserving the book's structure.\n", + "\n", + "Pseudocode:\n", + "for i from 1 to n:\n", + " new_page = generate_new_page() \n", + " encoded_book += new_page\n", + "\n", + " if length_of_page(new_page) > c:\n", + " excess_length = length_of_page(new_page) - c\n", + " new_page = trim_page(new_page, excess_length)\n", + " encoded_book = encoded_book[:-excess_length]\n" + ] + }, + { + "cell_type": "markdown", + "id": "53930468-cefc-4e61-a165-421e223f10f7", + "metadata": {}, + "source": [ + "## Reflection" + ] + }, + { + "cell_type": "raw", + "id": "75d916ad-4308-40a4-b34a-7ec98e950db9", + "metadata": {}, + "source": [ + "1. I used ChatGPT to read, to deepen my understanding of the problem, I tried to get it to tell me what the field of the problem was, what the nature of the problem was, and then after figuring it out, I went on to ask him if there were any other similar questions, and then I read and understood deeply, and then created my own questions and answered them. I also tried to use chatGPT to answer my questions. Interestingly, I found that chatGPT always gave me different answers, but I ultimately chose to stick with my answers.\n", + "\n", + "2. However, this time, chatGPT did not play a big role. The homework I designed covered the specific algorithm practice of kruskal, Prim, Dijkstra, judging whether a DAG can be topologically sorted, dynamic programming (01 knapsack), the use of the master theorem, and two proof problems that modeled examples. For the first six questions, the description of the questions is relatively simple and easy to understand, so I slightly used the following chatGPT understanding, and then drew the pictures myself and gave myself the questions. Only the last two questions, after I used it to deeply understand the nature, I was able to write my own questions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7d6c329f-f5d6-4bec-b2c8-aa68e893f22d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Go", + "language": "go", + "name": "gophernotes" + }, + "language_info": { + "codemirror_mode": "", + "file_extension": ".go", + "mimetype": "", + "name": "go", + "nbconvert_exporter": "", + "pygments_lexer": "", + "version": "go1.20" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Submissions/002734572_Douhao_Ma/Assignment2/pic1.jpg b/Submissions/002734572_Douhao_Ma/Assignment2/pic1.jpg new file mode 100644 index 0000000..6eb44c0 Binary files /dev/null and b/Submissions/002734572_Douhao_Ma/Assignment2/pic1.jpg differ diff --git a/Submissions/002734572_Douhao_Ma/Assignment2/pic2.jpg b/Submissions/002734572_Douhao_Ma/Assignment2/pic2.jpg new file mode 100644 index 0000000..16a853b Binary files /dev/null and b/Submissions/002734572_Douhao_Ma/Assignment2/pic2.jpg differ diff --git a/Submissions/002734572_Douhao_Ma/Assignment2/pic5.jpg b/Submissions/002734572_Douhao_Ma/Assignment2/pic5.jpg new file mode 100644 index 0000000..be68eb7 Binary files /dev/null and b/Submissions/002734572_Douhao_Ma/Assignment2/pic5.jpg differ diff --git a/Submissions/002734572_Douhao_Ma/Assignment3/.ipynb_checkpoints/Assignment3-checkpoint.ipynb b/Submissions/002734572_Douhao_Ma/Assignment3/.ipynb_checkpoints/Assignment3-checkpoint.ipynb new file mode 100644 index 0000000..363fcab --- /dev/null +++ b/Submissions/002734572_Douhao_Ma/Assignment3/.ipynb_checkpoints/Assignment3-checkpoint.ipynb @@ -0,0 +1,6 @@ +{ + "cells": [], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Submissions/002734572_Douhao_Ma/Assignment3/Assignment3.ipynb b/Submissions/002734572_Douhao_Ma/Assignment3/Assignment3.ipynb new file mode 100644 index 0000000..7796db7 --- /dev/null +++ b/Submissions/002734572_Douhao_Ma/Assignment3/Assignment3.ipynb @@ -0,0 +1,613 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "2243934e-1ba2-474a-99c6-3a099b1e6cad", + "metadata": {}, + "source": [ + "#### Question: Give brief definitions for the following:\n", + " i. Cut Capacity\n", + " ii. Residual Network\n", + " iii. Ford-Fulkerson Method\n", + " iv. Preflow-Push Algorithm\n", + " v. Edmonds-Karp Algorithm" + ] + }, + { + "cell_type": "markdown", + "id": "8bf1ed86-679b-4c72-9d8e-cb2d1c227e09", + "metadata": {}, + "source": [ + "Solution:\n", + "1. Cut Capacity\n", + "In the context of network flow, the cut capacity refers to the total weight or capacity of all edges crossing a cut in the network. Specifically, a cut is a division of the network's vertices into two disjoint subsets, with the source in one subset and the sink in the other. The cut capacity is critical in flow problems because it represents the maximum flow that can pass from the source to the sink — the smaller the cut capacity, the more it limits the flow through the network.\n", + "\n", + "2. Residual Network\n", + "A residual network is derived from an original flow network; it represents the network's capacity to accommodate additional flow. This is achieved by adjusting the original network's edges based on the current flow. The residual network is composed of the original edges minus the flow that is already passing through them (indicating remaining capacity) and backward edges indicating the amount of flow that can be potentially redirected or reversed.\n", + "\n", + "3. Ford-Fulkerson Method\n", + "The Ford-Fulkerson method is a greedy algorithm that computes the maximum flow in a flow network. The idea is to increase the flow in the network as much as possible by repeatedly finding \"augmenting paths\" (paths from the source to the sink in the residual network) and then adding this path's flow to the total flow, respecting the capacity constraints of the original network. The process is repeated until no more augmenting paths can be found in the residual network.\n", + "\n", + "4. Preflow-Push Algorithm\n", + "Also known as the push-relabel algorithm, the preflow-push algorithm is used to find the maximum flow in a flow network. Unlike the Ford-Fulkerson method, which focuses on augmenting paths, the preflow-push algorithm works by first initializing a \"preflow\" and then repeatedly performing \"push\" and \"relabel\" operations to move flow around the network until the flow is maximized. A \"push\" operation sends flow from a vertex to one of its neighbors, and a \"relabel\" operation modifies the \"height\" of a vertex to allow more flow to leave it.\n", + "\n", + "5. Edmonds-Karp Algorithm\n", + "The Edmonds-Karp algorithm is an implementation of the Ford-Fulkerson method for computing the maximum flow in a flow network. The main distinction of Edmonds-Karp is that it uses breadth-first search (BFS) to find the shortest augmenting path in the residual network in each iteration. The use of BFS ensures that the path found is the shortest in terms of the number of edges, which leads to a performance guarantee, or an upper bound, on the number of iterations the algorithm performs. This makes the Edmonds-Karp algorithm more efficient in practice compared to the original Ford-Fulkerson method when dealing with certain types of graphs." + ] + }, + { + "cell_type": "markdown", + "id": "245cb93b-14f3-4246-b7ed-9de3d721b4d6", + "metadata": {}, + "source": [ + "#### Question: Use the Bellman-Ford algorithm to find the shortest path from node A to F in the weighted directed graph. Show your work" + ] + }, + { + "cell_type": "markdown", + "id": "9ad0f7cf-f8d4-4ae7-a31c-e58c389c4088", + "metadata": {}, + "source": [ + "![Example Image](Q2.png)" + ] + }, + { + "cell_type": "raw", + "id": "1a735dbd-5550-4abb-96ab-1f8ce31758f9", + "metadata": {}, + "source": [ + "Solution\n", + "pseudo code:\n", + "function BellmanFord(graph, source):\n", + " distance = [∞,...,∞]\n", + " distance[source] = 0\n", + " predecessor = [null,...,null]\n", + "\n", + " for i from 1 to |V|-1:\n", + " for each edge (u, v) in graph.edges:\n", + " if distance[u] + weight(u, v) < distance[v]:\n", + " distance[v] = distance[u] + weight(u, v)\n", + " predecessor[v] = u\n", + "\n", + " for each edge (u, v) in graph.edges:\n", + " if distance[u] + weight(u, v) < distance[v]:\n", + " print \"Graph contains a negative-weight cycle\"\n", + " return\n", + "\n", + " return distance, predecessor\n", + "\n", + "function reconstructPath(predecessor, source, target):\n", + " path = []\n", + " while target != source:\n", + " path.prepend(target)\n", + " target = predecessor[target]\n", + " path.prepend(source)\n", + " return path" + ] + }, + { + "cell_type": "markdown", + "id": "7ae7f9c9-5775-46bd-93d1-9d5637a516a8", + "metadata": {}, + "source": [ + "Bellman-Ford Algorithm Explanation:\n", + "\n", + "Step 1: Initialization\n", + "Start by initializing the distance to all vertices as infinite (∞), except for the source vertex which will be initialized to zero (0).\n", + "Distance to A: 0 (because A is the source vertex)\n", + "Distance to B: ∞\n", + "Distance to C: ∞\n", + "Distance to D: ∞\n", + "Distance to E: ∞\n", + "\n", + "Step 2: Relaxation\n", + "The main idea is to relax all the edges, and this process is repeated for |V|-1 times, where |V| is the number of vertices in the graph. During each iteration:\n", + "\n", + "For each edge (u, v), if the distance to vertex u plus the weight of the edge (u, v) is less than the distance to vertex v, update the distance to vertex v and set its predecessor as vertex u.\n", + "\n", + "After the 1st iteration:\n", + "A -> C: The distance is updated to 2 because 0 (distance to A) + 2 (weight of A -> C) < ∞ (initial distance to C)\n", + "Using similar logic, distance to vertices B, D, and E are also updated.\n", + "After the 2nd iteration, distances may be updated further based on the relaxation condition.\n", + "The above process ensures that the shortest path to any vertex v is finalized after at most |V|-1 steps.\n", + "\n", + "Step 3: Check for Negative Weight Cycles\n", + "Once we've updated distances |V|-1 times, the algorithm checks for negative weight cycles. For every edge (u, v), if the distance to vertex u plus the weight of the edge (u, v) is less than the distance to vertex v, then the graph contains a negative weight cycle.\n", + "There are no negative weight cycles as evident from the given edge weights.\n", + "\n", + "Results:\n", + "Using the above steps, the algorithm will determine that the shortest path from A to D is through the path A -> C -> D with a total distance of 7." + ] + }, + { + "cell_type": "markdown", + "id": "f6315f77-7a82-4439-bdeb-e4efbd9e5c03", + "metadata": {}, + "source": [ + "#### Question: Use the e Ford-Fulkerson algorithm to find the shortest path from node A to F in the weighted directed graph. Show your work" + ] + }, + { + "cell_type": "markdown", + "id": "216e7eff-9a63-434f-802f-c67b5f2afc6a", + "metadata": {}, + "source": [ + "![Example Image](Q3.png)" + ] + }, + { + "cell_type": "raw", + "id": "5bf9d9d6-4523-4d14-8bb9-eff6761bd796", + "metadata": {}, + "source": [ + "Solution:\n", + "pseudo code:\n", + "function fordFulkerson(graph, source, sink):\n", + " max_flow = 0\n", + " residual_graph = create a copy of the input graph (initially)\n", + " while there is a path from source to sink in residual_graph using BFS:\n", + " path_flow = find the bottleneck value of the path (minimum capacity along the path)\n", + " update the residual_graph by reducing capacities along the path by path_flow and increasing the reverse edges by path_flow\n", + " max_flow += path_flow\n", + " return max_flow" + ] + }, + { + "cell_type": "markdown", + "id": "414929c8-eb8c-438b-9f82-70e4840799a3", + "metadata": {}, + "source": [ + "Steps:\n", + "\n", + "Step 1: Initialize the residual graph to be the same as the original graph.\n", + "\n", + "Step 2: While there exists an augmenting path from source A to sink D in the residual graph:\n", + "\n", + "Find the bottleneck value for the augmenting path. This is the smallest capacity along the path.\n", + "\n", + "Subtract the bottleneck value from all forward edges in the path and add the bottleneck value to all reverse edges.\n", + "\n", + "Repeat until no more augmenting paths can be found.\n", + "\n", + "Step 3: The maximum flow is the sum of flows on the outgoing edges from the source.\n", + "\n", + "Iteration 1:\n", + "Augmenting path: A -> C -> D\n", + "\n", + "Bottleneck value: min(2, 5) = 2\n", + "\n", + "Update the residual graph:\n", + "\n", + "Decrease the capacity of edge A->C to 0\n", + "Add the reverse edge C->A with capacity 2\n", + "Decrease the capacity of edge C->D to 3\n", + "Add the reverse edge D->C with capacity 2\n", + "Iteration 2:\n", + "Augmenting path: A -> B -> E -> D\n", + "\n", + "Bottleneck value: min(4, 4, 1) = 1\n", + "\n", + "Update the residual graph:\n", + "\n", + "Decrease the capacity of edge A->B to 3\n", + "Add the reverse edge B->A with capacity 1\n", + "Decrease the capacity of edge B->E to 3\n", + "Add the reverse edge E->B with capacity 1\n", + "Decrease the capacity of edge E->D to 0\n", + "Add the reverse edge D->E with capacity 1\n", + "Iteration 3:\n", + "Augmenting path: A -> C -> B -> E -> D\n", + "\n", + "Bottleneck value: min(0, 4, 3, 1) = 0 (This path doesn't work because of the A->C edge)\n", + "\n", + "We have to find another path.\n", + "\n", + "Iteration 4:\n", + "Augmenting path: A -> B -> C -> D\n", + "\n", + "Bottleneck value: min(3, 1, 3) = 1\n", + "\n", + "Update the residual graph:\n", + "\n", + "Decrease the capacity of edge A->B to 2\n", + "Add the reverse edge B->A with capacity 2\n", + "Decrease the capacity of edge B->C to 0\n", + "Add the reverse edge C->B with capacity 1\n", + "Decrease the capacity of edge C->D to 2\n", + "Add the reverse edge D->C with capacity 3\n", + "No more augmenting paths exist from A to D.\n", + "\n", + "Conclusion: The maximum flow from node A to node D is 2 + 1 + 1 = 4." + ] + }, + { + "cell_type": "markdown", + "id": "baf6a2c1-805e-4d8e-aaa4-e3d1d9bf5d59", + "metadata": {}, + "source": [ + "#### Question: Use the Preflow-Push (Push–relabel) maximum flow algorithm to find the maximum flow from node A to E in the weighted directed graph above. Show your work" + ] + }, + { + "cell_type": "markdown", + "id": "be11ff8c-8403-41b1-a629-02444988038b", + "metadata": {}, + "source": [ + "![Example Image](Q3.png)" + ] + }, + { + "cell_type": "raw", + "id": "ebe73d74-38f3-4503-9b44-895b9a2d47e3", + "metadata": {}, + "source": [ + "function preflowPush(graph, source, sink):\n", + " initialize preflow and heights for all nodes\n", + " height[source] = number of nodes in the graph\n", + " preflow[source] = infinity\n", + " for each edge (source, v):\n", + " flow[source, v] = capacity[source, v]\n", + " preflow[v] += capacity[source, v]\n", + " flow[v, source] = -capacity[source, v]\n", + "\n", + " while there exists an overflowing node u other than source and sink:\n", + " if there exists an adjacent node v to u such that height[u] > height[v]:\n", + " push(u, v)\n", + " else:\n", + " relabel(u)\n", + "\n", + " return preflow[sink]\n", + "\n", + "function push(u, v):\n", + " send = min(preflow[u], capacity[u, v] - flow[u, v])\n", + " flow[u, v] += send\n", + " flow[v, u] -= send\n", + " preflow[u] -= send\n", + " preflow[v] += send\n", + "\n", + "function relabel(u):\n", + " height[u] = 1 + min(height[v] for each edge (u, v) with positive residual capacity)" + ] + }, + { + "cell_type": "markdown", + "id": "eb3e61ab-edff-4360-a499-17dbe6c0adae", + "metadata": {}, + "source": [ + "Steps\n", + "Initialization:\n", + "\n", + "Initialize the preflow of each node to 0, except the source which is infinity.\n", + "Initialize the height of each node to 0, except the source which is the number of nodes.\n", + "Send as much flow as possible from the source to its neighbors.\n", + "Main Loop:\n", + "\n", + "While there's an overflowing vertex u:\n", + "Push: If there's an adjacent vertex v with a lower height and there's residual capacity between u and v, then push flow from u to v.\n", + "Relabel: If we can't push flow from u, then increase its height.\n", + "Let's solve:\n", + "\n", + "Initialization:\n", + "\n", + "Preflow: A=∞, B=0, C=0, D=0, E=0\n", + "Heights: A=5, B=0, C=0, D=0, E=0\n", + "Push as much flow from A:\n", + "\n", + "A->B: 4, A->C: 2. So, preflows are A=∞-6=∞, B=4, C=2.\n", + "Iteration 1:\n", + "\n", + "u = C (as it's overflowing)\n", + "Push from C->D: 2 (Bottleneck)\n", + "Preflow: A=∞, B=4, C=0, D=2, E=0\n", + "Iteration 2:\n", + "\n", + "u = B (as it's overflowing)\n", + "Push from B->E: 1 (Bottleneck)\n", + "Preflow: A=∞, B=3, C=0, D=2, E=1\n", + "Iteration 3:\n", + "\n", + "u = E (as it's overflowing)\n", + "Can't push, so Relabel E. New height of E = 1 + minimum height of neighbors with positive residual = 2 (considering D).\n", + "Push from E->D: 1\n", + "Preflow: A=∞, B=3, C=0, D=3, E=0\n", + "Iteration 4:\n", + "\n", + "u = B\n", + "Can't push, so Relabel B. New height of B = 1 + minimum height of neighbors with positive residual = 2 (considering E and C).\n", + "Push from B->C: 1\n", + "Preflow: A=∞, B=2, C=1, D=3, E=0\n", + "Iteration 5:\n", + "\n", + "u = C\n", + "Push from C->D: 1\n", + "Preflow: A=∞, B=2, C=0, D=4, E=0\n", + "No more overflowing vertices except source.\n", + "\n", + "Conclusion: The maximum flow from node A to node D is 4." + ] + }, + { + "cell_type": "markdown", + "id": "fd71bf17-63e5-4a35-b1d3-979b98dee5d4", + "metadata": {}, + "source": [ + "#### Question\n", + "Consider a flow network with edges of varying capacities. That is, a directed graph G=(V,E) with a source vertex s∈V, a target/sink vertex t∈V, and every edge e∈E has a capacity csube. The capacities are all positive integers. Given an integer parameter l≤∣E∣, your objective is to minimize the maximum flow of the network from s to t by reducing the capacity of l edges by one unit each. You need to determine which \n", + "l edges to decrement to achieve the smallest possible maximum flow.\n", + "\n", + "Provide a polynomial-time algorithm to determine the edges and ensure the maximum flow in the resultant graph G′=(V,E) is minimized." + ] + }, + { + "cell_type": "markdown", + "id": "2ce42734-9b6f-4069-b6ab-2db93c29ef9a", + "metadata": {}, + "source": [ + "Solution:\n", + "If the minimum s-t cut in the original graph has a total capacity of C, and C≤l, we can reduce the flow to 0 by reducing the capacity of the edges in the cut by one unit each until we've used up l units. \n", + "\n", + "If not, let's say f>l be the value of the minimum s-t flow. We identify the minimum s-t cut (A,B), and decrement the capacity of up to l edges going out of A. The resulting sub-graph has a maximum flow value of at most f−l.\n", + "\n", + "However, we claim that for any set of edges F of size l, the sub-graph G′=(V,E−F) has an s-t flow value of at least f−l. This is because any cut (A,B) in G′ has at least f edges going out of A in the original graph G, and since we're only reducing the capacity by l units, there will still be at least f−l units of flow going out of A in G′. Thus, the minimum cut in G ′has a value of at least f−l, and so there exists a flow of at least this value." + ] + }, + { + "cell_type": "markdown", + "id": "87efc794-de05-442b-ba74-267822f74622", + "metadata": {}, + "source": [ + "#### Question\n", + "Imagine a large music festival happening in a city. There are m music enthusiasts distributed across the city who wish to attend the festival. The city has l entry gates where attendees can enter. However, due to logistical constraints, each music enthusiast can only access specific gates based on their current location.\n", + "\n", + "Moreover, to prevent overcrowding, the festival organizers want to ensure that the attendees are evenly distributed among the entry gates. Each gate should have at most [m/l] attendees.\n", + "\n", + "Provide a polynomial-time algorithm to determine whether it's possible to distribute the attendees in the desired manner given their current locations and accessible gates." + ] + }, + { + "cell_type": "markdown", + "id": "de3ff256-8a9f-4ede-b55b-ade22d26aa66", + "metadata": {}, + "source": [ + "Solution:\n", + "\n", + "1. Graph Construction:\n", + "- Create a source node s.\n", + "- Create a sink node t.\n", + "- For each of the m music enthusiasts, create a node E_i.\n", + "- For each of the l entry gates, create a node G_j.\n", + "- Connect the source node s to each of the E_i nodes with an edge of capacity 1.\n", + "- Connect each E_i node to the G_j nodes that they can access. These edges also have a capacity of 1.\n", + "- Connect each G_j node to the sink node t with an edge of capacity [m/l].\n", + "2. Algorithm:\n", + "- Construct the bipartite graph as described above.\n", + "- Use a max-flow algorithm, such as the Ford-Fulkerson algorithm, to find the maximum flow in this graph.\n", + "We claim that distributing the attendees evenly among the entry gates is feasible if and only if there is an s-t flow of value m. If there's a feasible way to distribute the attendees, then we send one unit of flow from s to t along each of the paths s, E_i, G_j, t, where attendee i enters through gate j. This flow respects the capacity constraints, especially on the edges (E_i, G_j), ensuring no gate is overcrowded.\n", + "\n", + "Conversely, if there's a flow of value m, then it can be integral. We assign attendee i to gate j if the edge (E_i, G_j) carries one unit of flow.\n", + "\n", + "The time complexity mainly depends on the max-flow algorithm applied to a graph with O(m + l) nodes and O(ml) edges." + ] + }, + { + "cell_type": "markdown", + "id": "41bd23b7-279e-498e-9023-aa1c0ca689e3", + "metadata": {}, + "source": [ + "#### Question\n", + "You are an expansion manager for the renowned coffee chain, \"Bean There, Done That,\" and are responsible for strategizing the brand's growth along Liberty Boulevard. The boulevard is N blocks long, with each block having precisely one potential spot for a new café. Each location i on a block has a projected revenue of ri > 0, determined by various factors like foot traffic, visibility, and competition.\n", + "\n", + "Your CEO is indifferent about the total number of new cafes; however, due to a non-compete clause in the franchise agreement, no two cafes can operate within adjacent blocks to prevent market saturation.\n", + "\n", + "Your mission is to select a subset of these N potential spots to establish new cafes in a way that the cumulative revenue from these locations is maximized, bearing in mind the restriction against opening cafes on neighboring blocks." + ] + }, + { + "cell_type": "raw", + "id": "1be56516-e3c7-4320-989e-2e1139814858", + "metadata": {}, + "source": [ + "1. Define the Sub Problems:\n", + " \n", + "Let's define dp[i] as the maximum profit that can be obtained from the first i locations (1 <= i <= N), considering the non-adjacency constraint. The sub-problem here is to find the maximum profit for each prefix of locations of length i.\n", + "\n", + "2. Present Your Recurrence:\n", + "To compute dp[i], we have two choices: to include location i or not. If we include location i, we cannot include location i-1, but we take the profit ri. If we don't include location i, the answer is the same as dp[i-1]. Therefore, our recurrence relation is:\n", + "\n", + "dp[i] = max(dp[i-2] + ri, dp[i-1])\n", + "\n", + "This equation states that the maximum profit from the first i locations is either the maximum profit from the first i-2 locations plus the revenue from location i (if we decide to include it) or the maximum profit from the first i-1 locations (if we decide not to include the ith loc\n", + "o.3.\n", + "\n", + "1.3 Prove your recurrence is correct:\n", + "To prove that this recurrence is correct, we need to show that it correctly considers all possibilities ateach step.\n", + "\n", + "If we include the ith location (earning a revenue of ri), we cannot include the (i-1)th location due to the adjacency constraint. Thus, the best profit we can achieve in this case is dp[i-2] + ri.\n", + "If we do not include the ith location, the adjacency constraint does not affect us, and the best profit we can achieve is the same as if we had only considered the first (i-1) locations, which is dp[i-1].\n", + "Since these are the only two options (to include or not include the ith location), and the recurrence takes the best of these two, i4.4.orrect.\n", + "\n", + "P.4 State and \n", + "rove Base Cases:\n", + "Base Case 1: dp[0] = 0. If there are no locations, no revenue can be generated.\n", + "Base Case 2: dp[1] = r1. If there is only one location, the maximum revenue is the revenue rom that location.\n", + "\n", + "Proof of Base Cases:\n", + "Base Case 1 is trivial because no locations mean no possible profit, hence dp[0] = 0.\n", + "For Base Case 2, since there's only one location, the adjacency constraint doesn't apply, and the only revenue you can generate is from that location itelf, hence dp[1] = r1.\n", + "\n", + "With these defined base cases and the recurrence relation, we can compute the answer for any N by building up the solutions to these sub-problems." + ] + }, + { + "cell_type": "markdown", + "id": "70174544-7ef1-4593-8fd0-7fbe31e0d51e", + "metadata": {}, + "source": [ + "#### Question: For each of the following recurrences, give an expression for the runtime T(n) if the recurrence can be solved with the Master Theorem. Otherwise, indicate that the Master Theorem does not apply.\n", + " i. T(n) = 3T(n/2) + n^2\n", + " ii. T(n) = 2T(n/3) + n^3\n", + " iii. T(n) = 3T(n/4) + n\n", + " iv. T(n) = 2nT(n/3) + n^2.5\n", + " v. T(n) = n^2T(n/2) + n^3.5" + ] + }, + { + "cell_type": "raw", + "id": "d187417f-4bcb-4884-9c6f-788918cb1d5e", + "metadata": {}, + "source": [ + "Solution: \n", + "\n", + "i. T(n) = 3T(n/2) + n^2\n", + "a = 4, b = 2, and f(n) = n^2\n", + "Here, a = b^c, where c = 2. So, it falls into Case 2 of the Master Theorem.\n", + "T(n) = Θ(n^c * log n) = Θ(n^2 * log n)\n", + "\n", + "ii. T(n) = 2T(n/3) + n^3\n", + "a = 5, b = 3, and f(n) = n^3\n", + "Here, a > b^c, where c = 3. So, it falls into Case 1 of the Master Theorem.\n", + "T(n) = Θ(n^c) = Θ(n^3)\n", + "\n", + "iii. T(n) = 3T(n/4) + n\n", + "a = 2, b = 4, and f(n) = n\n", + "Here, a < b^c for any positive c. So, it falls into Case 1 of the Master Theorem.\n", + "T(n) = Θ(n^c) = Θ(1)\n", + "\n", + "iv. T(n) = 2nT(n/3) + n^2.5\n", + "Master Theorem does not apply A is a function of n.\n", + "\n", + "v. T(n) = n^2T(n/2) + n^3.5\n", + "Master Theorem does not apply A is a function of n." + ] + }, + { + "cell_type": "markdown", + "id": "800a41c4-7ded-497b-9348-9cffe4418ace", + "metadata": {}, + "source": [ + "#### Question \n", + "You have a knapsack with a capacity of W, and you have 6 items with their respective weights and values as follows:\n", + "\n", + "- Item 1: Weight 2, Value 3\n", + "- Item 2: Weight 3, Value 4\n", + "- Item 3: Weight 1, Value 2\n", + "- Item 4: Weight 4, Value 10\n", + "- Item 5: Weight 5, Value 11\n", + "- Item 6: Weight 2, Value 3\n", + "\n", + "Your task is to choose which items to put into the knapsack, such that the total weight does not exceed the knapsack's capacity W, and the total value of the items is maximized.\n", + "What items should you choose to maximize the total value, and what is the maximum total value you can achieve?" + ] + }, + { + "cell_type": "raw", + "id": "31420ea7-ff3e-490f-853d-bf1d2602cb74", + "metadata": {}, + "source": [ + "Solution:\n", + "Pseudocode: \n", + "Initialize a 2D array dp[n+1][W+1] with zeros\n", + "for i from 1 to n:\n", + " for j from 1 to W:\n", + " if weights[i-1] > j:\n", + " dp[i][j] = dp[i-1][j]\n", + " else:\n", + " dp[i][j] = max(dp[i-1][j], dp[i-1][j-weights[i-1]] + values[i-1])\n", + "\n", + "Initialize an empty list selected_items\n", + "i = n\n", + "j = W\n", + "while i > 0 and j > 0:\n", + " if dp[i][j] != dp[i-1][j]:\n", + " Add i to selected_items\n", + " j = j - weights[i-1]\n", + " Decrement i by 1" + ] + }, + { + "cell_type": "markdown", + "id": "9185b675-2d5c-4252-ba19-d191c5844ce5", + "metadata": {}, + "source": [ + "| Item/Capacity | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |\n", + "|---------------|----|----|----|----|----|----|----|----|----|----|----|----|----|----|\n", + "| Item 1 | 0 | 0 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |\n", + "| Item 2 | 0 | 0 | 3 | 4 | 4 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 7 |\n", + "| Item 3 | 0 | 2 | 3 | 5 | 5 | 7 | 8 | 8 | 10 | 10 | 10 | 10 | 10 | 10 |\n", + "| Item 4 | 0 | 2 | 3 | 5 | 10 | 12 | 13 | 15 | 15 | 17 | 20 | 22 | 23 | 25 |\n", + "| Item 5 | 0 | 2 | 3 | 5 | 10 | 12 | 13 | 15 | 21 | 23 | 24 | 26 | 26 | 28 |\n", + "| Item 6 | 0 | 2 | 3 | 5 | 10 | 12 | 15 | 15 | 21 | 23 | 26 | 26 | 29 | 29 |\n" + ] + }, + { + "cell_type": "raw", + "id": "2b89fae6-f547-4805-9758-79d38d795f03", + "metadata": {}, + "source": [ + "Based on the dynamic programming table provided:\n", + "\n", + "The maximum total value achievable is 29, which is the maximum value obtainable for a knapsack with a capacity of 13.\n", + "To reach this maximum value, the items you should choose are:\n", + "Item 1: Weight 2, Value 3\n", + "Item 4: Weight 4, Value 10\n", + "Item 5: Weight 5, Value 11\n", + "Item 6: Weight 2, Value 3\n", + "These four items have a combined weight of 13 (2 + 4 + 5 + 2 = 13) and a combined value of 27 (3 + 10 + 11 + 3 = 27), consistent with the results in the dynamic programming table.\n", + "\n", + "Therefore, with a knapsack capacity of 13, to maximize the total value, we should select items 1, 4, 5, and 6." + ] + }, + { + "cell_type": "markdown", + "id": "0e49a671-a125-446e-8028-cf555a674c84", + "metadata": {}, + "source": [ + "## Reflection\n", + "Using ChatGPT for homework assistance involved a process where the primary goal was leveraging its comprehension and creative capabilities to deepen my understanding of the task at hand, expand my thought process, and generate similar, novel questions based on the originals. Below, I detail the specific steps involved, the challenges encountered, the solutions adopted, and the insights and reflections gained from this experience.\n", + "\n", + "Process:\n", + "\n", + "Understanding the Template Questions: I initiated the process by inputting the assignment's questions into ChatGPT. These questions often required in-depth understanding and analysis. Through interacting with ChatGPT, I sought not only a surface-level interpretation but also a deeper exploration of the underlying concepts and themes.\n", + "Creating Similar Questions: Once ChatGPT comprehended the initial questions, I asked it to generate new ones, mirroring the core ideas of the original. This step tested whether it grasped the questions truly and could produce new problems requiring resolutions to the same central issues.\n", + "Answering the Questions: Finally, I tackled these newly crafted questions myself, applying the knowledge gleaned from the original questions, and attempting to solve them.\n", + "Challenges and Solutions:\n", + "\n", + "Contextual Understanding: At times, ChatGPT might not fully apprehend the deeper implications or complex context behind a question. When this occurred, I tried reformulating my queries or providing more background information to help the model understand better.\n", + "Quality of Generated Questions: In some instances, the questions created by ChatGPT were overly simplistic, lacking the complexity or depth of the original problems. To address this, I provided feedback and pinpointed aspects needing improvement, guiding ChatGPT towards producing more complex and relevant questions.\n", + "Insights and Reflections:\n", + "\n", + "Enhanced Conceptual Understanding: This process was remarkably beneficial in broadening my comprehension of the topics at hand. By engaging with ChatGPT, I could explore various angles and facets of a problem, enhancing my critical thinking skills.\n", + "Creativity in Problem-Solving: Generating new questions forced me to think outside the box and apply concepts in novel ways. It was an exercise in creative thinking, as much as it was in problem-solving.\n", + "AI's Limitations and Human Oversight: The experience underscored the importance of human oversight. AI, as advanced as ChatGPT, still had moments of misunderstanding or oversimplification. It reinforced that while AI can be a valuable tool for education, it doesn't replace human judgment and intuition.\n", + "Ethical Considerations: Relying on AI for educational tasks brought forth ethical considerations, such as maintaining academic integrity and ensuring original thought in responses. It's crucial to use such tools responsibly, ensuring they assist in the learning process rather than just providing answers.\n", + "In conclusion, using ChatGPT as a study aid was an enlightening experience that bolstered my understanding and problem-solving skills but also highlighted the critical need for human oversight and ethical responsibility in using AI tools." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "841e7a57-1051-4fee-a905-11adf80533df", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Go", + "language": "go", + "name": "gophernotes" + }, + "language_info": { + "codemirror_mode": "", + "file_extension": ".go", + "mimetype": "", + "name": "go", + "nbconvert_exporter": "", + "pygments_lexer": "", + "version": "go1.20" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Submissions/002734572_Douhao_Ma/Assignment3/Q2.png b/Submissions/002734572_Douhao_Ma/Assignment3/Q2.png new file mode 100644 index 0000000..e6eccdf Binary files /dev/null and b/Submissions/002734572_Douhao_Ma/Assignment3/Q2.png differ diff --git a/Submissions/002734572_Douhao_Ma/Assignment3/Q3.png b/Submissions/002734572_Douhao_Ma/Assignment3/Q3.png new file mode 100644 index 0000000..6c8efed Binary files /dev/null and b/Submissions/002734572_Douhao_Ma/Assignment3/Q3.png differ diff --git a/Submissions/002734572_Douhao_Ma/Assignment4/.ipynb_checkpoints/Assignment4-checkpoint.ipynb b/Submissions/002734572_Douhao_Ma/Assignment4/.ipynb_checkpoints/Assignment4-checkpoint.ipynb new file mode 100644 index 0000000..8c1a1f6 --- /dev/null +++ b/Submissions/002734572_Douhao_Ma/Assignment4/.ipynb_checkpoints/Assignment4-checkpoint.ipynb @@ -0,0 +1,298 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a44910c1-dbb3-4be6-b928-4a930292fbc6", + "metadata": {}, + "source": [ + "## Assignment4" + ] + }, + { + "cell_type": "markdown", + "id": "0421f3fb-44e4-4f45-b337-6149c235299a", + "metadata": {}, + "source": [ + "Q1" + ] + }, + { + "cell_type": "raw", + "id": "2d7e0d11-e722-4933-88a9-8a73240df564", + "metadata": {}, + "source": [ + "Given a weighted undirected graph G=(V,E,W), where V is a set of vertices, E is a set of edges, and W is a set of weights corresponding to each edge, a minimum spanning tree (MST) is a subset of the edges that connects all the vertices, without any cycles and with the minimum possible total edge weight. The MST problem asks whether a given undirected graph has a minimum spanning tree and to find that tree.\n", + "\n", + "A: Is the minimum spanning tree problem solvable in polynomial time? If so, provide the algorithm that solves it." + ] + }, + { + "cell_type": "raw", + "id": "f7c3da4a-befb-4ca1-86c4-5813c947e516", + "metadata": {}, + "source": [ + "Answer: \n", + "The minimum spanning tree problem is indeed solvable in polynomial time. The most common algorithms for finding the MST of a graph is Prim's algorithm.\n", + "Prim's Algorithm Approach:\n", + "Prim's algorithm also finds a minimum spanning tree for a graph which is a weighted connected undirected graph. It functions as follows:\n", + "1.\n", + "Start with any vertex as the current ver\n", + "te2.\n", + "Choose the least weighted edge connected to the current vertex that has not yet been added to the MST and which does not form a cyc3. l3. e.\n", + "Add the chosen edge and vertex to the M4. ST.\n", + "Repeat step 2 until all vertices are included in the MST.\n", + "The complexity of Prim's algorithm depends on the data structures used for the graph and can etween O(E+VlogV) to O(V^2).\n", + "O(V \n", + "2\n", + " )." + ] + }, + { + "cell_type": "raw", + "id": "fb8d113d-b9b8-463e-becb-10b5695d8907", + "metadata": {}, + "source": [ + "B: Consider a weighted undirected graph G=(V,E,W), where W represents the weights of the edges. Define a \"weighted-cycle-cover\" as a set of cycles in G such that each vertex v∈V belongs to a cycle, and the sum of the weights in each cycle is less than or equal to a given threshold T. This is known as the T-weighted-cycle-cover problem. Is the T-weighted-cycle-cover problem in NP? If so, demonstrate why." + ] + }, + { + "cell_type": "raw", + "id": "504c843e-5aa8-48af-b835-2b0fd9620541", + "metadata": {}, + "source": [ + "Answer:\n", + "The T-weighted-cycle-cover problem is a variation of the cycle cover problem with an additional constraint on the sum of the weights of the edges in each cycle.\n", + "\n", + "Just like the 3-cycle-cover problem, the T-weighted-cycle-cover problem can be classified as being in NP because a nondeterministic algorithm can guess a set of cycles and then verify in polynomial time whether each vertex is part of a cycle and the sum of the weights of each cycle does not exceed T.\n", + "\n", + "To prove this:\n", + "\n", + "Given a certificate, which is a set of cycles, we first check that each cycle is valid in the graph by verifying that the edges exist and are connected to form a cycle.\n", + "We then calculate the sum of the weights for each cycle using the weights given by W and check that this sum does not exceed T.\n", + "Lastly, we verify that every vertex in V is included in at least one cycle in the certificate.\n", + "The checking process involves verifying edges and weights, both of which can be done in polynomial time relative to the size of the graph, thus confirming that the problem is in NP. However, whether the problem is NP-complete would require a further reduction from a known NP-complete problem, which is beyond the scope of this question." + ] + }, + { + "cell_type": "raw", + "id": "75cb39d2-5404-4fe9-93be-9d069411a5c2", + "metadata": {}, + "source": [ + "C: Is the T-weighted-cycle-cover problem NP-complete? If so, provide a reduction from a known NP-complete problem to prove it." + ] + }, + { + "cell_type": "raw", + "id": "bdd15916-7c36-4ed5-ad06-ce29da731e1f", + "metadata": {}, + "source": [ + "Answer: \n", + "To determine if the T-weighted-cycle-cover problem is NP-complete, we must establish that it is both in NP and that any problem in NP can be reduced to it in polynomial time.\n", + "\n", + "The T-weighted-cycle-cover problem is in NP because a nondeterministic machine can guess a set of cycles and then verify in polynomial time that each vertex is part of a cycle and that the sum of the weights of the edges in each cycle is at most T.\n", + "\n", + "To prove NP-completeness, we need to show a reduction from a known NP-complete problem. One candidate for such a reduction is the Hamiltonian Cycle problem, which is NP-complete. The Hamiltonian Cycle problem asks whether a cycle visits each vertex exactly once.\n", + "\n", + "Reduction: Given an instance of the Hamiltonian Cycle problem, construct an instance of the T-weighted-cycle-cover problem by setting T to be the sum of the weights of all edges in the graph and assigning a weight of 1 to each edge. Now, a cycle cover in this constructed graph with a weight at most T that includes all vertices corresponds to a Hamiltonian cycle in the original graph. If a T-weighted-cycle-cover exists in the constructed graph, the cycle cover must include every vertex exactly once to stay within the weight limit T, which corresponds to a Hamiltonian cycle in the original graph.\n", + "Conversely, if a Hamiltonian cycle exists in the original graph, then the corresponding cycle cover in the constructed graph is a valid T-weighted-cycle-cover, with the total weight equal to the number of vertices, which is This reduction can be done in polynomial time since the graph construction and weight assignment are polynomial-time operations.\n", + "\n", + "Therefore, since we can reduce the Hamiltonian Cycle problem to the T-weighted-cycle-cover problem in polynomial time, the T-weighted-cycle-cover problem is NP-hard. Given that it is also in NP, we conclude that the T-weighted-cycle-cover problem is NP-complete." + ] + }, + { + "cell_type": "markdown", + "id": "20dd1bc9-0c3e-4675-9fb2-2904ff4ba6a5", + "metadata": {}, + "source": [ + "Q2" + ] + }, + { + "cell_type": "raw", + "id": "493fbf78-f30a-4e47-bad6-629054b8d8eb", + "metadata": {}, + "source": [ + "Consider the Weighted Directed Disjoint Paths Problem defined as follows: We are given a weighted directed graph G=(V,E,W) and pairs of nodes (s1,t 1), (s2,t2),...,(sk,tk). Each edge in E has an associated weight from the set W. The problem is to decide whether there exist node-disjoint paths P1, P2, ..., PK such that Pi is a minimum-weight path from si to ti, and no two paths share any common vertices. Determine whether the Weighted Directed Disjoint Paths Problem is NP-complete." + ] + }, + { + "cell_type": "raw", + "id": "80d98249-5335-4baa-aa6c-f4b6701d4f16", + "metadata": {}, + "source": [ + "Answer:\n", + "The Weighted Directed Disjoint Paths Problem is a more complex variant of the Directed Disjoint Paths Problem because it adds the constraint of finding the minimum-weight paths. This problem is in NP because, given a set of k paths, we can verify in polynomial time whether each path is node-disjoint from the others and whether each path is the minimum-weight path from si to ti.\n", + "\n", + "To show that the problem is NP-hard, we can reduce from the Directed Disjoint Paths Problem, which is known to be NP-complete. The reduction can proceed as follows: Given an instance of the Directed Disjoint Paths Problem, assign a weight of 1 to each edge in the graph. A solution to the Weighted Directed Disjoint Paths Problem on this instance will also solve the original problem because the minimum-weight path in a graph where all weights are equal is simply any path that connects the endpoints (since all paths have the same weight).\n", + "\n", + "Since the Directed Disjoint Paths Problem is NP-hard and we can reduce it to the Weighted Directed Disjoint Paths Problem, it implies that our weighted version is also NP-hard. Hence, as the Weighted Directed Disjoint Paths Problem is both in NP and NP-hard, it is NP-complete." + ] + }, + { + "cell_type": "markdown", + "id": "bd60c99f-6a9c-4993-bde0-e51cfc110b9c", + "metadata": {}, + "source": [ + "Q3" + ] + }, + { + "cell_type": "raw", + "id": "aa346c77-5833-480d-a292-ea06e909322e", + "metadata": {}, + "source": [ + "You are planning a multidisciplinary research project and need experts from various fields such as biology, chemistry, physics, computer science, etc. You have a list of n different research tasks that need to be performed and a pool of m potential researchers. Each researcher has expertise in a subset of tasks. The goal is to hire the smallest possible number of researchers to cover all n tasks. This is known as the Optimal Research Team problem. Is the Optimal Research Team problem NP-complete?" + ] + }, + { + "cell_type": "raw", + "id": "6e9dc10d-57b1-4136-a86d-0ef03a95ac7f", + "metadata": {}, + "source": [ + "Answer: \n", + "The Optimal Research Team problem is a computational problem that can be framed as follows:\n", + "\n", + "1. The problem is in NP: Given a team of researchers, it can be verified in polynomial time whether all n tasks are covered by checking each researcher's list of expertise against the tasks.\n", + "2. To show that the problem is NP-complete, we perform a reduction from the Set Cover problem, which is known to be NP-complete. Given an instance of the Set Cover problem with a universe U of elements and a collection of subsets S, we map each element in U to a research task and each subset in S to a researcher's expertise set. Finding a minimum set cover in this context is equivalent to hiring the smallest number of researchers to cover all tasks.\n", + "3. The reduction is polynomial-time computable because it involves a simple mapping of elements and subsets to tasks and researchers' expertise.\n", + "\n", + "Thus, since the Optimal Research Team problem can be reduced from the Set Cover problem, and the Set Cover problem is NP-complete, the Optimal Research Team problem is also NP-complete." + ] + }, + { + "cell_type": "markdown", + "id": "cd462ec4-71c3-4061-9cdd-013341cd99b4", + "metadata": {}, + "source": [ + "Q4" + ] + }, + { + "cell_type": "raw", + "id": "cbc4535c-3103-4c5d-aae4-455f6b06c975", + "metadata": {}, + "source": [ + "Suppose you are coordinating a multi-disciplinary academic conference. The conference features a series of talks across n different subjects. You have received proposals from m potential speakers. Each speaker has expertise in a subset of subjects. For each of the n subjects, there is some subset of the m speakers qualified to give a talk on it. The problem is: For a given number k < m, is it possible to schedule at most k speakers such that all n subjects will be covered in the talks? This problem is termed the Optimal Speaker Schedule problem." + ] + }, + { + "cell_type": "raw", + "id": "f21fe1fa-6cd2-44db-84f1-85f52ff81711", + "metadata": {}, + "source": [ + "Answer:\n", + "The Optimal Speaker Schedule problem is NP-complete, and here's why:\n", + "\n", + "1. The problem is in NP: Given a schedule of k speakers, we can verify in polynomial time whether all n subjects are covered by checking each speaker's list of expertise.\n", + "2. To prove that the problem is NP-complete, we can reduce the Set Cover problem. In the Set Cover problem, we are given a universe U of elements and a collection of subsets of U, and the task is to find the smallest collection of these subsets whose union equals U.\n", + "3. Reduction process: We can map each subject in the conference to an element of U and each speaker's expertise to a subset in the Set Cover problem. A solution to the Set Cover problem that covers all elements of U with the smallest number of subsets corresponds to scheduling the smallest number of speakers to cover all subjects at the conference.\n", + "4. This reduction is computable in polynomial time because it requires a simple assignment of subjects to elements and speakers' expertise to subsets.\n", + "\n", + "Therefore, since we can reduce the well-known NP-complete Set Cover problem to the Optimal Speaker Schedule problem, the latter is also NP-complete." + ] + }, + { + "cell_type": "markdown", + "id": "0d93e48b-71bb-4202-86d6-7b458ba0c57e", + "metadata": {}, + "source": [ + "Q5" + ] + }, + { + "cell_type": "raw", + "id": "9e5fa52d-0c63-4442-97c2-4bee5808e018", + "metadata": {}, + "source": [ + "There is a roster of n different community service events and m volunteers who have signed up. Each volunteer is available for certain events but has conflicts with others. \n", + "A: The objective is to maximize the number of volunteer-event pairings such that each event has at least one volunteer and no volunteer is assigned to an event they cannot attend." + ] + }, + { + "cell_type": "raw", + "id": "5ca4bd12-6f59-4452-9de4-c22e65c70e5b", + "metadata": {}, + "source": [ + "Answer:\n", + "Model this as a maximum flow problem to find the optimal volunteer assignments.\n", + "\n", + "Algorithm:\n", + "1. Create two special nodes: a source node 'S' and a sink node 'T'.\n", + "2. For every event 'Ei', where 'i' ranges from 1 to n, create a corresponding node in the graph.\n", + "3. For every volunteer 'Vj', where 'j' ranges from 1 to m, also create a corresponding node.\n", + "4. Draw an edge from the source node 'S' to each volunteer node 'Vj' with a capacity of 1, indicating that a volunteer can only be assigned to one event.\n", + "5. Draw an edge from each event node 'Ei' to the sink node 'T' with a capacity of 1, indicating that each event needs one volunteer.\n", + "6. For each pair of volunteer 'Vj' and event 'Ei' where the volunteer is available, draw an edge from 'Vj' to 'Ei' with a capacity of 1.\n", + "7. Apply a maximum flow algorithm like Ford-Fulkerson to find the maximum number of assignments.\n", + "\n", + "The maximum flow in this graph from 'S' to 'T' represents the highest number of volunteer-event pairings where each volunteer is assigned to an event they can attend, and each event has at least one volunteer. This approach ensures that the volunteer scheduling is optimized given the constraints." + ] + }, + { + "cell_type": "raw", + "id": "283ded66-0462-4956-b415-3e3269fb2a35", + "metadata": {}, + "source": [ + "B: Can all m volunteers always be matched with one of the n events? Prove that it can or cannot." + ] + }, + { + "cell_type": "raw", + "id": "a580431d-78f7-4a17-b95e-aa102e2b6f05", + "metadata": {}, + "source": [ + "Answer: \n", + "It's possible to match all volunteers to events if each event has at least one volunteer available and there are as many or more volunteers than events. If any event has zero volunteers available or there are more events than volunteers, then not all events can be matched with a volunteer. This can be determined by analyzing the volunteer-event graph and applying a maximum matching algorithm. If the algorithm finds a matching equal to the number of events, then all events can be successfully matched with a volunteer." + ] + }, + { + "cell_type": "markdown", + "id": "a1149f83-54a8-4322-a3c1-84d8821e817b", + "metadata": {}, + "source": [ + "## Reflection" + ] + }, + { + "cell_type": "raw", + "id": "d6bdd50b-1093-458c-9861-d06eb361b474", + "metadata": {}, + "source": [ + "Utilizing ChatGPT for aid in my study tasks was a methodology aimed at capitalizing on its understanding and inventive prowess to enrich my grasp of the given assignments, broaden my cognitive approaches, and originate questions that are akin yet innovative, based on the initial ones. Herein, I elucidate the specific maneuvers undertaken, the hurdles faced, the strategies implemented, and the wisdom and contemplations derived from this venture.\n", + "\n", + "Deciphering the Baseline Queries: The commencement of this endeavor involved feeding the homework queries into ChatGPT. These inquiries often demanded comprehensive comprehension and analytical prowess. My interaction with ChatGPT was not limited to a superficial interpretation but extended to an in-depth investigation of the foundational principles and motifs.\n", + "\n", + "Formulating Analogous Queries: After ChatGPT assimilated the essence of the initial queries, I prompted it to formulate new ones that echoed the fundamental concepts of the original set. This phase was crucial to assess its genuine grasp of the queries and its ability to spawn novel challenges revolving around the same key issues.\n", + "\n", + "Responding to the Queries: Subsequently, I engaged with these newly minted queries myself, utilizing the insights gathered from the original set and striving for resolutions.\n", + "\n", + "Contextual Grasping: Occasionally, ChatGPT might falter in fully grasping the intricate nuances of the complex backdrop of a query. In such instances, I resorted to rephrasing my questions or furnishing additional contextual details to enhance the model's comprehension.\n", + "\n", + "The caliber of the Formulated Queries: There were moments when the questions generated by ChatGPT lacked the sophistication or depth equivalent to the original problems. To remedy this, I offered critiques and highlighted areas in need of enhancement, steering ChatGPT toward creating more intricate and pertinent queries.\n", + "\n", + "Augmented Conceptual Insight: Engaging in this procedure proved exceptionally beneficial in widening my understanding of the subject matter. The interaction with ChatGPT allowed me to explore different perspectives and dimensions of a problem, thereby refining my analytical thinking abilities." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Submissions/002734572_Douhao_Ma/Assignment4/Assignment4.ipynb b/Submissions/002734572_Douhao_Ma/Assignment4/Assignment4.ipynb new file mode 100644 index 0000000..8c1a1f6 --- /dev/null +++ b/Submissions/002734572_Douhao_Ma/Assignment4/Assignment4.ipynb @@ -0,0 +1,298 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a44910c1-dbb3-4be6-b928-4a930292fbc6", + "metadata": {}, + "source": [ + "## Assignment4" + ] + }, + { + "cell_type": "markdown", + "id": "0421f3fb-44e4-4f45-b337-6149c235299a", + "metadata": {}, + "source": [ + "Q1" + ] + }, + { + "cell_type": "raw", + "id": "2d7e0d11-e722-4933-88a9-8a73240df564", + "metadata": {}, + "source": [ + "Given a weighted undirected graph G=(V,E,W), where V is a set of vertices, E is a set of edges, and W is a set of weights corresponding to each edge, a minimum spanning tree (MST) is a subset of the edges that connects all the vertices, without any cycles and with the minimum possible total edge weight. The MST problem asks whether a given undirected graph has a minimum spanning tree and to find that tree.\n", + "\n", + "A: Is the minimum spanning tree problem solvable in polynomial time? If so, provide the algorithm that solves it." + ] + }, + { + "cell_type": "raw", + "id": "f7c3da4a-befb-4ca1-86c4-5813c947e516", + "metadata": {}, + "source": [ + "Answer: \n", + "The minimum spanning tree problem is indeed solvable in polynomial time. The most common algorithms for finding the MST of a graph is Prim's algorithm.\n", + "Prim's Algorithm Approach:\n", + "Prim's algorithm also finds a minimum spanning tree for a graph which is a weighted connected undirected graph. It functions as follows:\n", + "1.\n", + "Start with any vertex as the current ver\n", + "te2.\n", + "Choose the least weighted edge connected to the current vertex that has not yet been added to the MST and which does not form a cyc3. l3. e.\n", + "Add the chosen edge and vertex to the M4. ST.\n", + "Repeat step 2 until all vertices are included in the MST.\n", + "The complexity of Prim's algorithm depends on the data structures used for the graph and can etween O(E+VlogV) to O(V^2).\n", + "O(V \n", + "2\n", + " )." + ] + }, + { + "cell_type": "raw", + "id": "fb8d113d-b9b8-463e-becb-10b5695d8907", + "metadata": {}, + "source": [ + "B: Consider a weighted undirected graph G=(V,E,W), where W represents the weights of the edges. Define a \"weighted-cycle-cover\" as a set of cycles in G such that each vertex v∈V belongs to a cycle, and the sum of the weights in each cycle is less than or equal to a given threshold T. This is known as the T-weighted-cycle-cover problem. Is the T-weighted-cycle-cover problem in NP? If so, demonstrate why." + ] + }, + { + "cell_type": "raw", + "id": "504c843e-5aa8-48af-b835-2b0fd9620541", + "metadata": {}, + "source": [ + "Answer:\n", + "The T-weighted-cycle-cover problem is a variation of the cycle cover problem with an additional constraint on the sum of the weights of the edges in each cycle.\n", + "\n", + "Just like the 3-cycle-cover problem, the T-weighted-cycle-cover problem can be classified as being in NP because a nondeterministic algorithm can guess a set of cycles and then verify in polynomial time whether each vertex is part of a cycle and the sum of the weights of each cycle does not exceed T.\n", + "\n", + "To prove this:\n", + "\n", + "Given a certificate, which is a set of cycles, we first check that each cycle is valid in the graph by verifying that the edges exist and are connected to form a cycle.\n", + "We then calculate the sum of the weights for each cycle using the weights given by W and check that this sum does not exceed T.\n", + "Lastly, we verify that every vertex in V is included in at least one cycle in the certificate.\n", + "The checking process involves verifying edges and weights, both of which can be done in polynomial time relative to the size of the graph, thus confirming that the problem is in NP. However, whether the problem is NP-complete would require a further reduction from a known NP-complete problem, which is beyond the scope of this question." + ] + }, + { + "cell_type": "raw", + "id": "75cb39d2-5404-4fe9-93be-9d069411a5c2", + "metadata": {}, + "source": [ + "C: Is the T-weighted-cycle-cover problem NP-complete? If so, provide a reduction from a known NP-complete problem to prove it." + ] + }, + { + "cell_type": "raw", + "id": "bdd15916-7c36-4ed5-ad06-ce29da731e1f", + "metadata": {}, + "source": [ + "Answer: \n", + "To determine if the T-weighted-cycle-cover problem is NP-complete, we must establish that it is both in NP and that any problem in NP can be reduced to it in polynomial time.\n", + "\n", + "The T-weighted-cycle-cover problem is in NP because a nondeterministic machine can guess a set of cycles and then verify in polynomial time that each vertex is part of a cycle and that the sum of the weights of the edges in each cycle is at most T.\n", + "\n", + "To prove NP-completeness, we need to show a reduction from a known NP-complete problem. One candidate for such a reduction is the Hamiltonian Cycle problem, which is NP-complete. The Hamiltonian Cycle problem asks whether a cycle visits each vertex exactly once.\n", + "\n", + "Reduction: Given an instance of the Hamiltonian Cycle problem, construct an instance of the T-weighted-cycle-cover problem by setting T to be the sum of the weights of all edges in the graph and assigning a weight of 1 to each edge. Now, a cycle cover in this constructed graph with a weight at most T that includes all vertices corresponds to a Hamiltonian cycle in the original graph. If a T-weighted-cycle-cover exists in the constructed graph, the cycle cover must include every vertex exactly once to stay within the weight limit T, which corresponds to a Hamiltonian cycle in the original graph.\n", + "Conversely, if a Hamiltonian cycle exists in the original graph, then the corresponding cycle cover in the constructed graph is a valid T-weighted-cycle-cover, with the total weight equal to the number of vertices, which is This reduction can be done in polynomial time since the graph construction and weight assignment are polynomial-time operations.\n", + "\n", + "Therefore, since we can reduce the Hamiltonian Cycle problem to the T-weighted-cycle-cover problem in polynomial time, the T-weighted-cycle-cover problem is NP-hard. Given that it is also in NP, we conclude that the T-weighted-cycle-cover problem is NP-complete." + ] + }, + { + "cell_type": "markdown", + "id": "20dd1bc9-0c3e-4675-9fb2-2904ff4ba6a5", + "metadata": {}, + "source": [ + "Q2" + ] + }, + { + "cell_type": "raw", + "id": "493fbf78-f30a-4e47-bad6-629054b8d8eb", + "metadata": {}, + "source": [ + "Consider the Weighted Directed Disjoint Paths Problem defined as follows: We are given a weighted directed graph G=(V,E,W) and pairs of nodes (s1,t 1), (s2,t2),...,(sk,tk). Each edge in E has an associated weight from the set W. The problem is to decide whether there exist node-disjoint paths P1, P2, ..., PK such that Pi is a minimum-weight path from si to ti, and no two paths share any common vertices. Determine whether the Weighted Directed Disjoint Paths Problem is NP-complete." + ] + }, + { + "cell_type": "raw", + "id": "80d98249-5335-4baa-aa6c-f4b6701d4f16", + "metadata": {}, + "source": [ + "Answer:\n", + "The Weighted Directed Disjoint Paths Problem is a more complex variant of the Directed Disjoint Paths Problem because it adds the constraint of finding the minimum-weight paths. This problem is in NP because, given a set of k paths, we can verify in polynomial time whether each path is node-disjoint from the others and whether each path is the minimum-weight path from si to ti.\n", + "\n", + "To show that the problem is NP-hard, we can reduce from the Directed Disjoint Paths Problem, which is known to be NP-complete. The reduction can proceed as follows: Given an instance of the Directed Disjoint Paths Problem, assign a weight of 1 to each edge in the graph. A solution to the Weighted Directed Disjoint Paths Problem on this instance will also solve the original problem because the minimum-weight path in a graph where all weights are equal is simply any path that connects the endpoints (since all paths have the same weight).\n", + "\n", + "Since the Directed Disjoint Paths Problem is NP-hard and we can reduce it to the Weighted Directed Disjoint Paths Problem, it implies that our weighted version is also NP-hard. Hence, as the Weighted Directed Disjoint Paths Problem is both in NP and NP-hard, it is NP-complete." + ] + }, + { + "cell_type": "markdown", + "id": "bd60c99f-6a9c-4993-bde0-e51cfc110b9c", + "metadata": {}, + "source": [ + "Q3" + ] + }, + { + "cell_type": "raw", + "id": "aa346c77-5833-480d-a292-ea06e909322e", + "metadata": {}, + "source": [ + "You are planning a multidisciplinary research project and need experts from various fields such as biology, chemistry, physics, computer science, etc. You have a list of n different research tasks that need to be performed and a pool of m potential researchers. Each researcher has expertise in a subset of tasks. The goal is to hire the smallest possible number of researchers to cover all n tasks. This is known as the Optimal Research Team problem. Is the Optimal Research Team problem NP-complete?" + ] + }, + { + "cell_type": "raw", + "id": "6e9dc10d-57b1-4136-a86d-0ef03a95ac7f", + "metadata": {}, + "source": [ + "Answer: \n", + "The Optimal Research Team problem is a computational problem that can be framed as follows:\n", + "\n", + "1. The problem is in NP: Given a team of researchers, it can be verified in polynomial time whether all n tasks are covered by checking each researcher's list of expertise against the tasks.\n", + "2. To show that the problem is NP-complete, we perform a reduction from the Set Cover problem, which is known to be NP-complete. Given an instance of the Set Cover problem with a universe U of elements and a collection of subsets S, we map each element in U to a research task and each subset in S to a researcher's expertise set. Finding a minimum set cover in this context is equivalent to hiring the smallest number of researchers to cover all tasks.\n", + "3. The reduction is polynomial-time computable because it involves a simple mapping of elements and subsets to tasks and researchers' expertise.\n", + "\n", + "Thus, since the Optimal Research Team problem can be reduced from the Set Cover problem, and the Set Cover problem is NP-complete, the Optimal Research Team problem is also NP-complete." + ] + }, + { + "cell_type": "markdown", + "id": "cd462ec4-71c3-4061-9cdd-013341cd99b4", + "metadata": {}, + "source": [ + "Q4" + ] + }, + { + "cell_type": "raw", + "id": "cbc4535c-3103-4c5d-aae4-455f6b06c975", + "metadata": {}, + "source": [ + "Suppose you are coordinating a multi-disciplinary academic conference. The conference features a series of talks across n different subjects. You have received proposals from m potential speakers. Each speaker has expertise in a subset of subjects. For each of the n subjects, there is some subset of the m speakers qualified to give a talk on it. The problem is: For a given number k < m, is it possible to schedule at most k speakers such that all n subjects will be covered in the talks? This problem is termed the Optimal Speaker Schedule problem." + ] + }, + { + "cell_type": "raw", + "id": "f21fe1fa-6cd2-44db-84f1-85f52ff81711", + "metadata": {}, + "source": [ + "Answer:\n", + "The Optimal Speaker Schedule problem is NP-complete, and here's why:\n", + "\n", + "1. The problem is in NP: Given a schedule of k speakers, we can verify in polynomial time whether all n subjects are covered by checking each speaker's list of expertise.\n", + "2. To prove that the problem is NP-complete, we can reduce the Set Cover problem. In the Set Cover problem, we are given a universe U of elements and a collection of subsets of U, and the task is to find the smallest collection of these subsets whose union equals U.\n", + "3. Reduction process: We can map each subject in the conference to an element of U and each speaker's expertise to a subset in the Set Cover problem. A solution to the Set Cover problem that covers all elements of U with the smallest number of subsets corresponds to scheduling the smallest number of speakers to cover all subjects at the conference.\n", + "4. This reduction is computable in polynomial time because it requires a simple assignment of subjects to elements and speakers' expertise to subsets.\n", + "\n", + "Therefore, since we can reduce the well-known NP-complete Set Cover problem to the Optimal Speaker Schedule problem, the latter is also NP-complete." + ] + }, + { + "cell_type": "markdown", + "id": "0d93e48b-71bb-4202-86d6-7b458ba0c57e", + "metadata": {}, + "source": [ + "Q5" + ] + }, + { + "cell_type": "raw", + "id": "9e5fa52d-0c63-4442-97c2-4bee5808e018", + "metadata": {}, + "source": [ + "There is a roster of n different community service events and m volunteers who have signed up. Each volunteer is available for certain events but has conflicts with others. \n", + "A: The objective is to maximize the number of volunteer-event pairings such that each event has at least one volunteer and no volunteer is assigned to an event they cannot attend." + ] + }, + { + "cell_type": "raw", + "id": "5ca4bd12-6f59-4452-9de4-c22e65c70e5b", + "metadata": {}, + "source": [ + "Answer:\n", + "Model this as a maximum flow problem to find the optimal volunteer assignments.\n", + "\n", + "Algorithm:\n", + "1. Create two special nodes: a source node 'S' and a sink node 'T'.\n", + "2. For every event 'Ei', where 'i' ranges from 1 to n, create a corresponding node in the graph.\n", + "3. For every volunteer 'Vj', where 'j' ranges from 1 to m, also create a corresponding node.\n", + "4. Draw an edge from the source node 'S' to each volunteer node 'Vj' with a capacity of 1, indicating that a volunteer can only be assigned to one event.\n", + "5. Draw an edge from each event node 'Ei' to the sink node 'T' with a capacity of 1, indicating that each event needs one volunteer.\n", + "6. For each pair of volunteer 'Vj' and event 'Ei' where the volunteer is available, draw an edge from 'Vj' to 'Ei' with a capacity of 1.\n", + "7. Apply a maximum flow algorithm like Ford-Fulkerson to find the maximum number of assignments.\n", + "\n", + "The maximum flow in this graph from 'S' to 'T' represents the highest number of volunteer-event pairings where each volunteer is assigned to an event they can attend, and each event has at least one volunteer. This approach ensures that the volunteer scheduling is optimized given the constraints." + ] + }, + { + "cell_type": "raw", + "id": "283ded66-0462-4956-b415-3e3269fb2a35", + "metadata": {}, + "source": [ + "B: Can all m volunteers always be matched with one of the n events? Prove that it can or cannot." + ] + }, + { + "cell_type": "raw", + "id": "a580431d-78f7-4a17-b95e-aa102e2b6f05", + "metadata": {}, + "source": [ + "Answer: \n", + "It's possible to match all volunteers to events if each event has at least one volunteer available and there are as many or more volunteers than events. If any event has zero volunteers available or there are more events than volunteers, then not all events can be matched with a volunteer. This can be determined by analyzing the volunteer-event graph and applying a maximum matching algorithm. If the algorithm finds a matching equal to the number of events, then all events can be successfully matched with a volunteer." + ] + }, + { + "cell_type": "markdown", + "id": "a1149f83-54a8-4322-a3c1-84d8821e817b", + "metadata": {}, + "source": [ + "## Reflection" + ] + }, + { + "cell_type": "raw", + "id": "d6bdd50b-1093-458c-9861-d06eb361b474", + "metadata": {}, + "source": [ + "Utilizing ChatGPT for aid in my study tasks was a methodology aimed at capitalizing on its understanding and inventive prowess to enrich my grasp of the given assignments, broaden my cognitive approaches, and originate questions that are akin yet innovative, based on the initial ones. Herein, I elucidate the specific maneuvers undertaken, the hurdles faced, the strategies implemented, and the wisdom and contemplations derived from this venture.\n", + "\n", + "Deciphering the Baseline Queries: The commencement of this endeavor involved feeding the homework queries into ChatGPT. These inquiries often demanded comprehensive comprehension and analytical prowess. My interaction with ChatGPT was not limited to a superficial interpretation but extended to an in-depth investigation of the foundational principles and motifs.\n", + "\n", + "Formulating Analogous Queries: After ChatGPT assimilated the essence of the initial queries, I prompted it to formulate new ones that echoed the fundamental concepts of the original set. This phase was crucial to assess its genuine grasp of the queries and its ability to spawn novel challenges revolving around the same key issues.\n", + "\n", + "Responding to the Queries: Subsequently, I engaged with these newly minted queries myself, utilizing the insights gathered from the original set and striving for resolutions.\n", + "\n", + "Contextual Grasping: Occasionally, ChatGPT might falter in fully grasping the intricate nuances of the complex backdrop of a query. In such instances, I resorted to rephrasing my questions or furnishing additional contextual details to enhance the model's comprehension.\n", + "\n", + "The caliber of the Formulated Queries: There were moments when the questions generated by ChatGPT lacked the sophistication or depth equivalent to the original problems. To remedy this, I offered critiques and highlighted areas in need of enhancement, steering ChatGPT toward creating more intricate and pertinent queries.\n", + "\n", + "Augmented Conceptual Insight: Engaging in this procedure proved exceptionally beneficial in widening my understanding of the subject matter. The interaction with ChatGPT allowed me to explore different perspectives and dimensions of a problem, thereby refining my analytical thinking abilities." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Submissions/002734572_Douhao_Ma/readme.md b/Submissions/002734572_Douhao_Ma/readme.md new file mode 100644 index 0000000..8e59355 --- /dev/null +++ b/Submissions/002734572_Douhao_Ma/readme.md @@ -0,0 +1,12 @@ +NUid : 002734572 + +FirstName: Douhao + +LastName: Ma + +Reflections are in the end of each assignments + +- [x] Assignment1 +- [x] Assignment2 2023-10-08 +- [x] Assignment3 2023-10-21 +- [x] Assignment4 2023-11-18 \ No newline at end of file