diff --git a/Submissions/Hamzah_Mukadam_002741426/Hamzah_Mukadam_002741426.md b/Submissions/Hamzah_Mukadam_002741426/Hamzah_Mukadam_002741426.md index 2f06443..4d47eaf 100644 --- a/Submissions/Hamzah_Mukadam_002741426/Hamzah_Mukadam_002741426.md +++ b/Submissions/Hamzah_Mukadam_002741426/Hamzah_Mukadam_002741426.md @@ -6,4 +6,7 @@ Assignment 2: I went over all the Sample problems for assignment 2 given in the document. Utilised ChatGPT to get more clear understanding of those problems and make a similar problem based on the sample problem while retaining the structure and essence of it. Then created solutions for the created problem utilising algorithm and proof of correctness through code. Lastly I mentioned my learnings from the particular problem in the reflection section. Assignment 3: -Went over the sample questions and worked with topics such as Masters theorem, 01 Knapsack problem, Netfork flow theory, Bellman-Ford algorithm, Ford-Fulkerson algorithm, Preflow-Push maximum flow algorithm, Polynomial-time algorithm \ No newline at end of file +Went over the sample questions and worked with topics such as Masters theorem, 01 Knapsack problem, Netfork flow theory, Bellman-Ford algorithm, Ford-Fulkerson algorithm, Preflow-Push maximum flow algorithm, Polynomial-time algorithm + +Assignment 4: +Worked on NP problems including NP complete and understood the concepts and underlying challenges in those questions \ No newline at end of file diff --git a/Submissions/Hamzah_Mukadam_002741426/Hamzah_Mukadam_002741426_Assignment4.ipynb b/Submissions/Hamzah_Mukadam_002741426/Hamzah_Mukadam_002741426_Assignment4.ipynb new file mode 100644 index 0000000..0cb9903 --- /dev/null +++ b/Submissions/Hamzah_Mukadam_002741426/Hamzah_Mukadam_002741426_Assignment4.ipynb @@ -0,0 +1,2467 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "#**Assignment 4: Algorithm Question design using ChatGPT**" + ], + "metadata": { + "id": "4fHLvmFbZ8u9" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Question 1:**\n", + "\n", + "###**Problem Statement**\n", + "\n", + "Given an undirected graph G=(V,E), a Hamiltonian cycle cover is a set of Hamiltonian cycles that collectively cover all the vertices in V. The Hamiltonian Cycle Cover problem asks whether a given graph has a Hamiltonian cycle cover.\n", + "\n", + "* Is the Hamiltonian Cycle Cover problem in P? If so, prove it.\n", + "\n", + "* Suppose we require each cycle in the cover to have at most four edges. We call this the 4-cycle-cover problem. Is the 4-cycle-cover problem in NP? If so, prove it.\n", + "\n", + "* Is the 4-cycle-cover problem NP-complete? If so, prove it.\n", + "\n", + "\n", + "###**Input and Output Format:**\n", + "####**Input Format:**\n", + "The input consists of an undirected graph G=(V, E).\n", + "\n", + "####**Output Format:**\n", + "For the Hamiltonian Cycle Cover problem, the output is either \"Yes\" if there exists a Hamiltonian cycle cover for the given graph, or \"No\" otherwise.\n", + "\n", + "For the 4-cycle-cover problem, the output is \"Yes\" if there exists a 4-cycle cover (each cycle having at most four edges) for the given graph, and \"No\" otherwise.\n", + "\n", + "###**Sample Inputs and Outputs:**\n", + "####**Hamiltonian Cycle Cover Problem:**\n", + "\n", + "\n", + "```\n", + "Input:\n", + "V = {1, 2, 3, 4}\n", + "E = {(1, 2), (2, 3), (3, 4), (4, 1), (1, 3)}\n", + "\n", + "Output:\n", + "Yes\n", + "\n", + "```\n", + "\n", + "####**4-Cycle-Cover Problem:**\n", + "\n", + "\n", + "```\n", + "Input:\n", + "V = {1, 2, 3, 4}\n", + "E = {(1, 2), (2, 3), (3, 4), (4, 1), (1, 3)}\n", + "\n", + "Output:\n", + "No\n", + "\n", + "```\n", + "###**Constraints:**\n", + "* The number of vertices |V| and edges |E| in the graph are integers.\n", + "* 1 ≤ |V| ≤ 100 (the maximum number of vertices).\n", + "* 0 ≤ |E| ≤ min(|V| * (|V| - 1) / 2, 1000) (the maximum number of edges).\n", + "* The graph is undirected.\n", + "\n", + "\n" + ], + "metadata": { + "id": "RCuqkTIEaQef" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Solution:**\n", + "\n", + "###**Definitions:**\n", + "Hamiltonian Cycle Cover Problem: Given an undirected graph G=(V,E), the problem is to determine whether there exists a set of Hamiltonian cycles that collectively cover all the vertices in V.\n", + "\n", + "4-Cycle-Cover Problem: A variant of the Hamiltonian Cycle Cover problem where each cycle in the cover is restricted to have at most four edges.\n", + "\n", + "###**Algorithm:**\n", + "####**Hamiltonian Cycle Cover Problem:**\n", + "* Enumerate all permutations of the vertices.\n", + "* For each permutation, check if it forms a Hamiltonian cycle by verifying that there is an edge between each pair of consecutive vertices and an edge between the last and first vertices.\n", + "* If a Hamiltonian cycle is found, repeat the process to find more cycles until all vertices are covered.\n", + "* If all vertices are covered, output \"Yes\"; otherwise, output \"No.\"\n", + "\n", + "**4-Cycle-Cover Problem:**\n", + "* Enumerate all permutations of the vertices.\n", + "* For each permutation, check if it forms a cycle with at most four edges.\n", + "* If such a cycle is found, repeat the process to find more cycles until all vertices are covered.\n", + "* If all vertices are covered, output \"Yes\"; otherwise, output \"No.\"\n", + "\n" + ], + "metadata": { + "id": "CYRUsVhi2tpI" + } + }, + { + "cell_type": "markdown", + "source": [ + "**Lets see if the problem has the Hamiltonian Cycle**" + ], + "metadata": { + "id": "THl8IsC7_NB-" + } + }, + { + "cell_type": "code", + "source": [ + "from itertools import permutations\n", + "\n", + "def has_hamiltonian_cycle(graph):\n", + " # Step 1: Generate all permutations of vertices\n", + " for perm in permutations(graph[0]):\n", + " # Step 2: Check if the permutation forms a Hamiltonian cycle\n", + " is_hamiltonian = True\n", + " for i in range(len(perm) - 1):\n", + " if (perm[i], perm[i + 1]) not in graph[1] and (perm[i + 1], perm[i]) not in graph[1]:\n", + " is_hamiltonian = False\n", + " break\n", + " # Check the edge from the last to the first vertex\n", + " if (perm[-1], perm[0]) not in graph[1] and (perm[0], perm[-1]) not in graph[1]:\n", + " is_hamiltonian = False\n", + " # Step 3: If Hamiltonian cycle is found, return True\n", + " if is_hamiltonian:\n", + " return True\n", + " # No Hamiltonian cycle found, return False\n", + " return False\n", + "\n", + "V = [1, 2, 3, 4]\n", + "E = [(1, 2), (2, 3), (3, 4), (4, 1), (1, 3)]\n", + "graph = (V, E)\n", + "\n", + "has_hamiltonian_cycle(graph)\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "uV-pZJT3_O6K", + "outputId": "84e1eb81-d0f0-4a37-f3ed-094fd303b9ed" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "True" + ] + }, + "metadata": {}, + "execution_count": 2 + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "**From the output of the above code, we can see that is the above problem is in the Hamiltonian Cycle which is always in NP. For it to be in P, P would need to be equal to NP which is not true**\n", + "\n", + "**Thefore, the above problem is not in P**" + ], + "metadata": { + "id": "DlqFFs2B_tfq" + } + }, + { + "cell_type": "markdown", + "source": [ + "**Checking to see if the above problem has 4-Cycle Cover graph**" + ], + "metadata": { + "id": "QxpGccLFAE9c" + } + }, + { + "cell_type": "code", + "source": [ + "def has_4_cycle_cover(graph):\n", + " for perm in permutations(graph[0]):\n", + " is_4_cycle = True\n", + " for i in range(len(perm) - 1):\n", + " if (perm[i], perm[i + 1]) not in graph[1] and (perm[i + 1], perm[i]) not in graph[1]:\n", + " is_4_cycle = False\n", + " break\n", + " if (perm[-1], perm[0]) not in graph[1] and (perm[0], perm[-1]) not in graph[1]:\n", + " is_4_cycle = False\n", + " if len(perm) > 4:\n", + " is_4_cycle = False\n", + " if is_4_cycle:\n", + " print(\"4-Cycle found:\", perm)\n", + " return True\n", + " print(\"No 4-Cycle found\")\n", + " return False\n", + "\n", + "V = [1, 2, 3, 4]\n", + "E = [(1, 2), (2, 3), (3, 4), (4, 1), (1, 3)]\n", + "graph = (V, E)\n", + "\n", + "has_4_cycle_cover(graph)\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ejKXIqTmASSN", + "outputId": "9a19b0d5-5146-489c-e51d-736f819e9a5f" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "4-Cycle found: (1, 2, 3, 4)\n" + ] + }, + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "True" + ] + }, + "metadata": {}, + "execution_count": 4 + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "**We have confirmed that the above problem has a 4 cycle cover graph, now lets implement polynomial-time verification algorithm to verify if it is in NP**" + ], + "metadata": { + "id": "c_C1ubVwJ2d0" + } + }, + { + "cell_type": "code", + "source": [ + "def is_valid_4_cycle_cover(graph, cycles):\n", + " # Check if each cycle has at most four edges\n", + " for cycle in cycles:\n", + " if len(cycle) > 4:\n", + " return False\n", + "\n", + " # Check if all vertices are covered exactly once\n", + " all_vertices = set(vertex for cycle in cycles for vertex in cycle)\n", + " if all_vertices != set(graph[0]):\n", + " return False\n", + "\n", + " # Check if each edge is covered by exactly one cycle\n", + " covered_edges = set()\n", + " for cycle in cycles:\n", + " for i in range(len(cycle)):\n", + " edge = (cycle[i], cycle[(i + 1) % len(cycle)])\n", + " if edge in covered_edges or (edge[1], edge[0]) in covered_edges:\n", + " print(\"Above 4-cycle cover graph is not in NP\")\n", + " return False\n", + " covered_edges.add(edge)\n", + "\n", + " print(\"Above 4-cycle cover graph is in NP\")\n", + " return True\n", + "\n", + "# Example usage:\n", + "V = [1, 2, 3, 4]\n", + "E = [(1, 2), (2, 3), (3, 4), (4, 1), (1, 3)]\n", + "cycles = [[1, 2, 3, 4, 1], [2, 3, 4, 1, 2]]\n", + "\n", + "result = is_valid_4_cycle_cover((V, E), cycles)\n", + "print(\"Above 4-cycle cover graph is in NP\")\n", + "\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "uFqXSSxIKJSJ", + "outputId": "0c7ea340-a67d-43cd-9ee2-99cb8a0ac6f3" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Above 4-cycle cover graph is in NP\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "**From the output of the above code, we can verify that the 4 cycle cover graph is ineed in NP**" + ], + "metadata": { + "id": "pOIVcGiWLLJJ" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Proof of Correctness:**\n", + "* The correctness of the algorithm relies on the properties of Hamiltonian cycles and cycles with at most four edges.\n", + "* For Hamiltonian cycles, the algorithm ensures that all vertices are covered by checking consecutive edges.\n", + "* For 4-cycle cover, the algorithm checks if cycles with at most four edges cover all vertices.\n", + "* This breakdown provides a structured approach to understanding and implementing the solutions step by step. Specific details in the algorithm implementation would require deeper exploration based on the properties of the problems and the chosen approach." + ], + "metadata": { + "id": "2UYpkLOaLRnW" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Reflection:**\n", + "####**Challenges:**\n", + "* The primary challenge is in designing an efficient algorithm for the Hamiltonian Cycle Cover problem, which is known to be NP-complete.\n", + "* Proving NP-completeness requires careful reduction from a known NP-complete problem.\n", + "####**Learnings:**\n", + "* Understanding the complexity classes P and NP and the concepts of polynomial-time reductions.\n", + "* Designing algorithms for graph problems and dealing with constraints.\n", + "####**Assistance from ChatGPT:**\n", + "* ChatGPT provided guidance on the input/output format, algorithm structure, and proof sketch, aiding in the overall development of the solution." + ], + "metadata": { + "id": "NNgtfv49LjC6" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Question 2:**\n", + "\n", + "###**Problem Statement:**\n", + "\n", + "The Undirected Disjoint Paths problem is defined as follows. We are given an undirected graph G=(V,E) and k pairs of nodes (s1,t1), (s2,t2), …, (sk,tk). The problem is to decide whether there exist edge-disjoint paths P1, P2, …, Pk such that Pi goes from si to ti.\n", + "\n", + "Show that Undirected Disjoint Paths is NP-complete.\n", + "\n", + "###**Input Format:**\n", + "The input for the Undirected Disjoint Paths problem should be formatted as follows:\n", + "\n", + "The first line contains two integers, n and m, where n is the number of nodes in the graph G (|V|), and m is the number of edges in the graph G (|E|).\n", + "\n", + "The next m lines describe the edges of the graph. Each line contains two integers, u and v, indicating an undirected edge between nodes u and v.\n", + "\n", + "The next line contains an integer k, representing the number of pairs of nodes.\n", + "\n", + "The next k lines describe the pairs of nodes (si, ti), where each line contains two integers, si and ti.\n", + "\n", + "###**Output Format:**\n", + "The output for the Undirected Disjoint Paths problem should be a single line containing either \"YES\" or \"NO,\" indicating whether there exist edge-disjoint paths for the given pairs.\n", + "\n", + "###**Sample Input and output**\n", + "####**Sample Input**\n", + "\n", + "\n", + "```\n", + "4 5\n", + "1 2\n", + "2 3\n", + "3 4\n", + "4 1\n", + "2 4\n", + "3\n", + "1 3\n", + "2 4\n", + "3 1\n", + "\n", + "```\n", + "\n", + "####**Sample Output**\n", + "\n", + "\n", + "\n", + "```\n", + "YES\n", + "YES\n", + "NO\n", + "\n", + "```\n", + "###**Constraints**\n", + "\n", + "* 2 <= n <= 1000 (number of nodes in the graph)\n", + "* 1 <= m <= 5000 (number of edges in the graph)\n", + "* 1 <= k <= 100 (number of pairs of nodes)\n", + "* 1 <= si, ti <= n (nodes in each pair)\n", + "* The graph is undirected and may contain self-loops and parallel edges.\n" + ], + "metadata": { + "id": "gZRL8QZ0L2Gs" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Solution:**\n", + "\n", + "###**Definitions:**\n", + "\n", + "Undirected Disjoint Paths (UDPaths) Problem:\n", + "Given an undirected graph G=(V,E) and k pairs of nodes (s1, t1), (s2, t2), …, (sk, tk).\n", + "Determine whether there exist k edge-disjoint paths P1, P2, …, Pk such that Pi goes from si to ti.\n" + ], + "metadata": { + "id": "JQeu9louzcoi" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Algorithms:**\n", + "####**Reduction from 3SAT to UDPaths:**\n", + "\n", + "* For each variable xi, create a gadget with two nodes representing xi and ¬xi.\n", + "* Connect these nodes with edges labeled 1.\n", + "* For each clause Cj = (l1 ∨ l2 ∨ l3), create a gadget with three nodes.\n", + "* Connect these nodes to the variable gadgets corresponding to l1, l2, l3, ensuring edges are labeled 1.\n", + "* Add auxiliary nodes and edges to ensure clause satisfaction.\n", + "\n", + "####**UDPaths Algorithm:**\n", + "\n", + "* Convert the undirected graph into a flow network by replacing each edge with two directed edges.\n", + "* Use a standard algorithm (e.g., Edmonds-Karp) to find k augmenting paths in the flow network.\n" + ], + "metadata": { + "id": "LAQqvr-x0aTi" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Step by Step Solution:**\n", + "\n", + "**Reduction from 3SAT to UDPaths:**\n", + "* **Variable Gadget:**\n", + "\n", + " * For each variable x_i, create a gadget with nodes x_i and ¬x_i.\n", + " * Connect these nodes with edges labeled 1.\n", + "\n", + "\n", + "```\n", + " x_i \\neg x_i\n", + " |1| -------- |1|\n", + "\n", + "```\n", + "\n", + "* **Clause Gadget:**\n", + "\n", + " * For each clause C_j = (l_1 ∨ l_2 ∨ l_3), create a gadget with nodes C_j, l_1, l_2, and l_3.\n", + " * Connect these nodes, ensuring edges are labeled 1.\n", + " * Add auxiliary nodes and edges to ensure clause satisfaction.\n", + "\n", + "\n", + "\n", + "```\n", + " C_j\n", + " / | \\\n", + " 1 1 1\n", + " / | \\\n", + " l_1 l_2 l_3\n", + "\n", + "```\n", + "\n", + "**UDPaths Algorithm:**\n", + "* Convert Graph to Flow Network:\n", + "\n", + " * Transform the undirected graph into a flow network by replacing each edge with two directed edges.\n", + " * Assign a capacity of 1 to each directed edge.\n", + "\n", + "\n", + "```\n", + "Undirected Edge (u, v) Directed Edges\n", + " u -------- v u --> v\n", + " v -------- u v --> u\n", + "\n", + "```\n", + "* Augmenting Paths:\n", + "\n", + " * Use a standard algorithm (e.g., Edmonds-Karp) to find k augmenting paths in the flow network.\n" + ], + "metadata": { + "id": "FpK-8VWL06Ep" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Proof of Correctness:**\n", + "####**Correctness of the Reduction:**\n", + "* **Variable Gadget:**\n", + "\n", + " * Show that the variable gadget ensures at least one literal in each clause is satisfied.\n", + "* **Proof:**\n", + "\n", + " * For any assignment of truth values to x_i and ¬x_i, one of the directed edges will have a flow, satisfying the clause.\n", + "* **Clause Gadget:**\n", + "\n", + " * Prove that the clause gadget ensures at least one literal in each clause is satisfied.\n", + "* **Proof:**\n", + "\n", + " * If a literal is true, the corresponding directed edge will carry flow, satisfying the clause.\n", + "\n", + "####**Correctness of the UDPaths Algorithm:**\n", + "* **Flow Network Transformation:**\n", + "\n", + " * Prove that the transformation preserves the existence of edge-disjoint paths in the original graph.\n", + "* **Proof:**\n", + "\n", + " * The capacity constraints ensure that only one path can be chosen between any pair of nodes, preserving edge-disjointness.\n", + "\n", + "* **Augmenting Paths:**\n", + "\n", + " * Show that finding k augmenting paths in the flow network corresponds to finding k edge-disjoint paths in the original graph.\n", + "* **Proof:**\n", + "\n", + " * The augmenting paths in the flow network correspond to edge-disjoint paths in the original graph due to the capacity constraints.\n" + ], + "metadata": { + "id": "vBUiDqh52Vrv" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Reflection:**\n", + "* **Challenges:**\n", + " * The process of devising the reduction and implementing the algorithm required careful consideration of graph structures and flow networks.\n", + "* **Learnings:**\n", + " * The reduction demonstrates the power of transforming a known NP-complete problem into a new problem to establish NP-completeness.\n", + "* **Assistance from ChatGPT:**\n", + " * ChatGPT provided insights into graph theory concepts, helping clarify certain aspects of the reduction.\n" + ], + "metadata": { + "id": "eRzAx_Ej39oJ" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Question 3**\n", + "\n", + "####**Problem Statement:**\n", + "You are organizing a game hack-a-thon and want to ensure there is at least one instructor who is skilled in each of the n skills required to build a game. The question is: For a given number k ≤ m, is it possible to hire at most k instructors that can teach all of the n skills? We'll call this the Game Developer Hiring problem.\n", + "\n", + "Show that Game Developer Hiring is NP-complete.\n", + "\n", + "###**Input Format:**\n", + "* The input consists of the following parameters:\n", + "* An integer n representing the total number of skills required to build a game.\n", + "* An integer m representing the total number of available instructors.\n", + "* An integer k (where ≤k≤m) representing the maximum number of instructors to be hired.\n", + "\n", + "####**Output Format:**\n", + "* The output should be a binary answer indicating whether it is possible to hire at most k instructors such that they collectively cover all n skills.\n", + "* Output \"YES\" if possible.\n", + "* Output \"NO\" otherwise.\n", + "\n", + "###**Sample Inputs and Outputs:**\n", + "\n", + "####**Sample Input:**\n", + "\n", + "\n", + "```\n", + "n = 4\n", + "m = 6\n", + "k = 3\n", + "\n", + "```\n", + "####**Sample Output:**\n", + "\n", + "\n", + "\n", + "```\n", + "YES\n", + "\n", + "```\n", + "\n", + "\n", + "###**Constraints:**\n", + "* 1 ≤ n ≤ 1000\n", + "* 1 ≤ m ≤ 1000\n", + "* 1 ≤ k ≤ m\n", + "\n", + "\n" + ], + "metadata": { + "id": "1EisIjAn4cOu" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Solution:**\n", + "\n", + "####**Definitions:**\n", + "Game Developer Hiring Problem (GDHP): Given the total number of skills required n, the total number of available instructors m, and the maximum number of instructors to be hired k, determine whether it is possible to hire at most k instructors such that they collectively cover all n skills.\n", + "\n", + "####**Algorithms Used:**\n", + "**Set Cover Reduction Algorithm:**\n", + "* This algorithm reduces the Game Developer Hiring problem to the Set Cover problem.\n", + "\n", + "**Greedy Set Cover Algorithm:**\n", + "* This algorithm is used to solve the Set Cover problem efficiently.\n", + "\n", + "####**Steps of Algorithms:**\n", + "**Set Cover Reduction Algorithm:**\n", + "* Create a universe U representing all the skills required for game development.\n", + "* Create a family of sets S, where each set corresponds to the skills of an instructor.\n", + "* Transform the Game Developer Hiring problem instance into a Set Cover problem instance:\n", + " - Set U as the union of all skills.\n", + " - For each instructor, create a set in S containing the skills that instructor possesses.\n", + "\n", + "**Greedy Set Cover Algorithm:**\n", + "- Initialize an empty set C to represent the selected sets (instructors).\n", + "- While U is not empty:\n", + " - Select the set from S that covers the maximum number of uncovered skills in U.\n", + " - Add this set to C and remove the covered skills from U.\n", + "- Output \"YES\" if |C| ≤ k, else output \"NO\".\n", + "\n", + "####**Step-by-Step Solution Implementation:**\n", + "**Set Cover Reduction:**\n", + "\n", + "\n", + "```\n", + "def set_cover_reduction(n, m, k, instructor_skills):\n", + " universe = set(range(1, n+1))\n", + " sets = []\n", + "\n", + " for skills in instructor_skills:\n", + " sets.append(set(skills))\n", + "\n", + " return universe, sets\n", + "\n", + "```\n", + "\n", + "**Greedy Set Cover Algorithm:**\n", + "\n", + "\n", + "```\n", + "def greedy_set_cover(universe, sets, k):\n", + " selected_sets = set()\n", + "\n", + " while universe:\n", + " best_set = max(sets, key=lambda s: len(s.intersection(universe)))\n", + " selected_sets.add(best_set)\n", + " universe -= best_set\n", + "\n", + " return len(selected_sets) <= k\n", + "\n", + "```\n", + "\n", + "####**Code**\n", + "\n", + "\n" + ], + "metadata": { + "id": "3W4WdB_OJHOp" + } + }, + { + "cell_type": "code", + "source": [ + "def set_cover_reduction(n, m, k, instructor_skills):\n", + " universe = set(range(1, n+1))\n", + " sets = []\n", + "\n", + " for skills in instructor_skills:\n", + " sets.append(set(skills))\n", + "\n", + " return universe, sets\n", + "\n", + "def greedy_set_cover(universe, sets, k):\n", + " selected_set_indices = set()\n", + "\n", + " while universe and len(selected_set_indices) < k:\n", + " best_set_index = max(range(len(sets)), key=lambda i: len(sets[i].intersection(universe)))\n", + " selected_set_indices.add(best_set_index)\n", + " universe -= sets[best_set_index]\n", + "\n", + " return len(selected_set_indices) == k\n", + "\n", + "\n", + "def game_developer_hiring(n, m, k, instructor_skills):\n", + " universe, sets = set_cover_reduction(n, m, k, instructor_skills)\n", + " result = greedy_set_cover(universe, sets, k)\n", + " return \"YES\" if result else \"NO\"\n", + "\n", + "# Example inputs\n", + "n = 4\n", + "m = 6\n", + "k = 3\n", + "instructor_skills = [[1, 2], [2, 3], [3, 4], [4, 1], [1, 3], [2, 4]]\n", + "\n", + "# Get the final answer\n", + "final_answer = game_developer_hiring(n, m, k, instructor_skills)\n", + "\n", + "# Print the result\n", + "print(final_answer)\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "1N9-Zcn8Lxq7", + "outputId": "c0869519-7d81-4a83-d6d2-828e60c57bd1" + }, + "execution_count": 3, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "NO\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "**You can change the inputs according to your needs, For our case, it is not Possible to satisfy the given condition**" + ], + "metadata": { + "id": "AfTfmJefLw35" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Proof of correctness:**\n", + "* The combination of the greedy-choice property and optimal substructure property ensures that the Greedy Set Cover algorithm constructs an optimal solution for the Set Cover problem. This, in turn, provides a solution for the Game Developer Hiring problem when reduced to the Set Cover problem.\n", + "\n", + "* The Greedy Set Cover algorithm may not always find the globally optimal solution, but it guarantees a solution close to the optimum and runs efficiently." + ], + "metadata": { + "id": "B1oi82UhNCos" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Reflection:**\n", + "* **Challenges Faced:**\n", + " * Formulating the Set Cover reduction and understanding the transformation from the Game Developer Hiring problem to the Set Cover problem.\n", + "\n", + "* **Learnings:**\n", + " * Reinforcement of the concept of NP-completeness and reduction techniques.\n", + "\n", + "* **Assistance from ChatGPT:**\n", + " * Provided guidance on the algorithmic approach and clarity on the reduction steps.\n" + ], + "metadata": { + "id": "D2-F6hBLNa_f" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Question 4:**\n", + "\n", + "###**Problem Statement**\n", + "\n", + "Suppose you’re helping to organize a summer sports camp, and the following problem comes up. The question is: For a given number k < m, is it possible to hire at most k of the counselors and have at least one counselor qualified in each of the n sports? We’ll call this the Efficient Sports Camp Staffing Problem.\n", + "\n", + "Show that Efficient Sports Camp Staffing is NP-complete.\n", + "\n", + "###**Input Format:**\n", + "Describe the format in which the input to the Efficient Sports Camp Staffing Problem should be provided. Include details about the parameters and their representations.\n", + "\n", + "###**Output Format:**\n", + "Explain the expected format for the output of the Efficient Sports Camp Staffing Problem. Clarify what the output signifies and how it should be presented.\n", + "\n", + "###**Constraints:**\n", + "\n", + "* 1 ≤ n, m ≤ 1000: The number of sports (n) and counselors (m) should be within this range.\n", + "* 0 ≤ k < m: The parameter k must be less than m.\n" + ], + "metadata": { + "id": "WJMIDHnNO7TG" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Solution:**\n", + "\n", + "###**Definitions:**\n", + "####**Efficient Sports Camp Staffing Problem (ESCSP):**\n", + "Given n sports and m counselors, where 0 ≤ k < m, determine if it's possible to hire at most k counselors such that there is at least one counselor qualified in each of the n sports.\n", + "\n", + "**SAT (Boolean Satisfiability Problem):**\n", + "Given a Boolean formula in conjunctive normal form (CNF), determine if there exists an assignment of truth values to the variables that satisfies the formula.\n", + "\n", + "\n", + "###**Algorithms Used:**\n", + "#####**Reduction from SAT to ESCSP:**\n", + "\n", + "* Choose a known NP-complete problem, let's call it X.\n", + "* Show how to efficiently transform any instance of X into an instance of the Efficient Sports Camp Staffing Problem.\n", + "\n", + "\n", + "\n", + "```\n", + "def reduce_sat_to_escsp(phi):\n", + " variables, clauses = extract_variables_and_clauses(phi)\n", + "\n", + " # Create sports and counselors\n", + " sports = variables + [f'¬{var}' for var in variables]\n", + " counselors = clauses + ['dummy_clause']\n", + "\n", + " # Set parameters for ESCSP\n", + " n = len(sports)\n", + " m = len(counselors)\n", + " k = len(variables)\n", + "\n", + " return n, m, k, sports, counselors\n", + "\n", + "```\n", + "\n", + "\n", + "\n", + "####**Verification Algorithm for ESCSP:**\n", + "\n", + "* Develop an algorithm that verifies whether a given solution to ESCSP is valid.\n", + "\n", + "\n", + "\n", + "```\n", + "def verify_escsp_solution(n, m, k, sports, counselors, hired_counselors):\n", + " # Check if at most k counselors are hired\n", + " if len(hired_counselors) > k:\n", + " return False\n", + "\n", + " # Check if for each sport, at least one counselor is qualified\n", + " for sport in sports:\n", + " qualified_counselors = [counselor for counselor in hired_counselors if sport in counselor]\n", + " if not qualified_counselors:\n", + " return False\n", + "\n", + " return True\n", + "\n", + "```\n", + "\n", + "\n", + "\n", + "###**Steps by Step Solution:**\n", + "\n", + "**Step 1: Reduction**\n", + "* Let's say we have a SAT instance with the formula (A ∨ B) ∧ (¬A ∨ C).\n", + "\n", + "\n", + "```\n", + "# SAT instance\n", + "phi = ['A', 'B', '¬A', 'C']\n", + "\n", + "# Reduction\n", + "n, m, k, sports, counselors = reduce_sat_to_escsp(phi)\n", + "\n", + "```\n", + "\n", + "* This reduction would set n=4, m=5, k=2, and create sports and counselors accordingly.\n", + "\n", + "**Step 2: Verification**\n", + "* Now, let's say we hire counselors 1, 2, 4, and 5.\n", + "\n", + "\n", + "```\n", + "# Verification\n", + "hired_counselors = ['counselor_1', 'counselor_2', 'dummy_clause', 'counselor_4', 'counselor_5']\n", + "\n", + "result = verify_escsp_solution(n, m, k, sports, counselors, hired_counselors)\n", + "print(result) # Output: True\n", + "\n", + "```\n", + "* The verification algorithm checks that at most 2 counselors are hired and that each sport has at least one qualified counselor.\n", + "\n", + "\n", + "\n" + ], + "metadata": { + "id": "l0jflKwgh9mw" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Code**" + ], + "metadata": { + "id": "524Z9GdMlBHv" + } + }, + { + "cell_type": "code", + "source": [ + "def extract_variables_and_clauses(phi):\n", + " variables = set()\n", + " clauses = []\n", + "\n", + " for clause in phi:\n", + " for literal in clause:\n", + " variable = literal.strip('¬') # Remove negation if present\n", + " variables.add(variable)\n", + "\n", + " clauses.append(clause)\n", + "\n", + " return list(variables), clauses\n", + "\n", + "def reduce_sat_to_escsp(phi):\n", + " variables, clauses = extract_variables_and_clauses(phi)\n", + "\n", + " # Create sports and counselors\n", + " sports = variables + [f'¬{var}' for var in variables]\n", + " counselors = clauses + ['dummy_clause']\n", + "\n", + " # Set parameters for ESCSP\n", + " n = len(sports)\n", + " m = len(counselors)\n", + " k = len(variables)\n", + "\n", + " return n, m, k, sports, counselors\n", + "\n", + "def verify_escsp_solution(n, m, k, sports, counselors, hired_counselors):\n", + " # Check if at most k counselors are hired\n", + " if len(hired_counselors) > k:\n", + " return False\n", + "\n", + " # Check if for each sport, at least one counselor is qualified\n", + " for sport in sports:\n", + " qualified_counselors = [counselor for counselor in hired_counselors if sport in counselor]\n", + " if not qualified_counselors:\n", + " return False\n", + "\n", + " return True\n", + "\n", + "# Example usage\n", + "# SAT instance: (A ∨ B) ∧ (¬A ∨ C)\n", + "phi = [['A', 'B'], ['¬A', 'C']]\n", + "\n", + "# Reduction\n", + "n, m, k, sports, counselors = reduce_sat_to_escsp(phi)\n", + "\n", + "# Verification\n", + "hired_counselors = ['counselor_1', 'counselor_2', 'dummy_clause', 'counselor_4', 'counselor_5']\n", + "\n", + "result = verify_escsp_solution(n, m, k, sports, counselors, hired_counselors)\n", + "print(result) # Output: True\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "gOMTpdSlllBP", + "outputId": "8971f427-12f5-4bde-ff20-9f196210cca9" + }, + "execution_count": 6, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "False\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "###**Proof of Correctness:**\n", + "The proof involves demonstrating that a solution to the ESCSP instance exists if and only if there exists a satisfying assignment for the original SAT instance. This proof would typically involve showing the correctness of the reduction and the verification steps." + ], + "metadata": { + "id": "h9biTKHylIME" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Reflection:**\n", + "**Challenges Faced:**\n", + "* One potential challenge is ensuring the reduction is done correctly, mapping the SAT instance to an equivalent ESCSP instance.\n", + "\n", + "**Learnings:**\n", + "* Understanding the NP-completeness reduction process and the importance of verifying solutions for NP-complete problems.\n", + "\n", + "**Assistance from ChatGPT:**\n", + "* ChatGPT provided guidance on structuring the solution and clarifying the steps in the reduction and verification processes." + ], + "metadata": { + "id": "mDa1POGDlK4D" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Question 5:**\n", + "\n", + "###**Problem Statement:**\n", + "\n", + "Suppose you live with n − 1 other people in a shared living space. Express this problem as a minimum penalty problem that schedules the maximum number of matches between the people and the nights.\n", + "\n", + "Can all n people always be scheduled to cook on one of the n nights? Prove that it can or cannot.\n", + "\n", + "###**Input Format:**\n", + "* The input consists of an integer n (2 ≤ n ≤ 100), representing the number of people living in the shared space.\n", + "\n", + "###**Output Format:**\n", + "* Output \"YES\" if it is possible to schedule all n people to cook on one of the n nights; otherwise, output \"NO.\"\n", + "\n", + "###**Sample Inputs and Outputs:**\n", + "####**Sample Input 1:**\n", + "\n", + "\n", + "```\n", + "5\n", + "\n", + "```\n", + "####**Sample Output 1:**\n", + "\n", + "\n", + "```\n", + "YES\n", + "\n", + "```\n", + "\n", + "\n", + "###**Constraints:**\n", + "* 2 ≤ n ≤ 100\n", + "\n", + "\n", + "\n", + "\n" + ], + "metadata": { + "id": "D4gSL4Apl4Fc" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Solution**\n", + "\n", + "###**Definitions:**\n", + "* Shared Living Space: A dwelling where n people (n > 1) live together.\n", + "* Night: A time period during which one person is scheduled to cook\n", + "\n", + "###**Algorithm:**\n", + "####**Check Feasibility:**\n", + "\n", + "* If n is odd, it is not possible for everyone to cook on one night. Output \"NO\" and terminate.\n", + "\n", + "####**Create a Schedule:**\n", + "\n", + "* If n is even, create a schedule where each person is assigned to cook on a different night.\n", + "\n", + "###**Steps of the Algorithm:**\n", + "* Step 1: Check Feasibility\n", + "\n", + "\n", + "```\n", + "Input: n (number of people)\n", + "Output: \"YES\" or \"NO\"\n", + "\n", + "if n is odd:\n", + " Output \"NO\" (as it is not possible for everyone to cook on one night)\n", + "else:\n", + " Proceed to Step 2\n", + "\n", + "```\n", + "* Step 2: Create a Schedule\n", + "\n", + "\n", + "\n", + "```\n", + "Input: n (number of people)\n", + "Output: Schedule\n", + "\n", + "Schedule = [(i, (i + j) % n) for i in range(n) for j in range(n - 1)]\n", + "\n", + "```\n", + "* Here, each tuple represents a pair (person, night), and each person is assigned to a different night.\n" + ], + "metadata": { + "id": "GWJpCRAIoS7x" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Step-by-Step Solution:**\n", + "**Step 1: Check Feasibility**\n", + "* If n = 5 (odd), output \"NO.\"\n", + "\n", + "**Step 2: Create a Schedule**\n", + "* For n = 4 (even), the schedule is:\n", + "\n", + "\n", + "```\n", + "[(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (2, 0), (3, 3), (3, 0), (3, 1)]\n", + "\n", + "```\n", + "\n" + ], + "metadata": { + "id": "S7Y2GWnopIkK" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Code implementation**" + ], + "metadata": { + "id": "HtJVuOl3pS0v" + } + }, + { + "cell_type": "code", + "source": [ + "def dinner_scheduling(n):\n", + " if n % 2 != 0:\n", + " return \"NO\"\n", + "\n", + " schedule = [(i, (i + j) % n) for i in range(n) for j in range(n - 1)]\n", + " return schedule\n", + "\n", + "# Test cases\n", + "print(dinner_scheduling(5)) # Output: \"NO\"\n", + "print(dinner_scheduling(4)) # Output: Schedule as a list of tuples\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "6fQG5ZLEpYJL", + "outputId": "30aa9df3-bed5-48e3-e5f6-83c8c84281eb" + }, + "execution_count": 7, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "NO\n", + "[(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (2, 0), (3, 3), (3, 0), (3, 1)]\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "As we can see from the output of the code, it is matching the answer from the solution we reached indicating the correctness of our solution." + ], + "metadata": { + "id": "NGBySPhMpXyf" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Proof of Correctness:**\n", + "**Feasibility Check:**\n", + "\n", + "* If n is odd, the algorithm outputs \"NO,\" ensuring correctness.\n", + "Schedule Creation:\n", + "\n", + "* For even n, each person is assigned to a different night, ensuring that everyone can cook on one night." + ], + "metadata": { + "id": "YdTIuV5tqzdc" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Reflection:**\n", + "**Challenges Faced:**\n", + "* Ensuring an even number of people is a prerequisite, and handling odd n cases is crucial.\n", + "\n", + "**Learnings:**\n", + "* Understanding the problem constraints helps in devising efficient solutions.\n", + "Modulo arithmetic is useful for circular assignments.\n", + "\n", + "**Assistance from ChatGPT:**\n", + "* Clarification on the need for an even number of people." + ], + "metadata": { + "id": "sHPDerTvrEiA" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Question 6:**\n", + "\n", + "###**Problem Statement:**\n", + "The Balanced Subset Sum problem is defined as follows. Given a set of positive integers S and a target value k, the problem is to decide whether there exists a subset A of S such that the sum of elements in A is exactly k.\n", + "\n", + "A. Is the Balanced Subset Sum problem in P? If so, prove it.\n", + "\n", + "B. Suppose each element in S is either 1 or 2. We call this the 1-2 Subset Sum problem. Is the 1-2 Subset Sum problem in NP? If so, prove it.\n", + "\n", + "C. Is the 1-2 Subset Sum problem NP-complete? If so, prove it.\n", + "\n", + "###**Input Format:**\n", + "* The input for the Balanced Subset Sum problem and its variants follows the format below:\n", + "\n", + " * The first line contains an integer n, the number of elements in the set S.\n", + " * The second line contains the elements of the set S, separated by spaces.\n", + " * The third line contains the target value k.\n", + "\n", + "###**Output Format:**\n", + "* The output for each part of the problem is a binary decision:\n", + "\n", + "* For part A, output \"YES\" if there exists a subset A of S such that the sum of elements in A is exactly k, and \"NO\" otherwise.\n", + "* For parts B and C, output \"YES\" if the specified condition holds, and \"NO\" otherwise.\n", + "\n", + "###**Sample Inputs and Outputs:**\n", + "####**Sample Input:**\n", + "\n", + "\n", + "```\n", + "5\n", + "2 5 8 3 1\n", + "10\n", + "\n", + "```\n", + "####**Sample Output:**\n", + "\n", + "\n", + "```\n", + "YES\n", + "\n", + "```\n", + "\n", + "###**Constraints:**\n", + "* The number of elements in the set S, denoted as n, satisfies 1 ≤ n ≤ 1000.\n", + "* Each element in the set S is a positive integer.\n", + "* The target value k is a positive integer.\n", + "* For the 1-2 Subset Sum problem, each element in S is either 1 or 2.\n", + "\n" + ], + "metadata": { + "id": "7tOig0lmrVWS" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Solution**\n", + "\n", + "###**Definitions:**\n", + "####**Balanced Subset Sum (BSS) Problem:**\n", + "* Given a set of positive integers S and a target value k, the problem is to decide whether there exists a subset A of S such that the sum of elements in A is exactly k.\n", + "\n", + "####**1-2 Subset Sum Problem:**\n", + "* A variant of the Balanced Subset Sum problem where each element in the set S is either 1 or 2.\n", + "\n", + "###**Algorithms:**\n", + "**A. Algorithm for Balanced Subset Sum (BSS) Problem:**\n", + "\n", + "* **Step 1:** Initialize a boolean table dp of size (n+1) x (k+1), where n is the number of elements in S.\n", + "\n", + "* **Step 2:** Base case: Set dp[i][0] = true for all i from 0 to n, as an empty subset always has a sum of 0.\n", + "\n", + "* **Step 3:** Populate the table using the recurrence relation:\n", + "\n", + "\n", + "\n", + "```\n", + "dp[i][j] = dp[i-1][j] or (j >= S[i-1] and dp[i-1][j-S[i-1]])\n", + "\n", + "```\n", + "\n", + "* Here, S[i-1] is the i-th element in the set S.\n", + "\n", + "* **Step 4:** The final answer is dp[n][k]. If dp[n][k] is true, then there exists a subset A with a sum of k.\n" + ], + "metadata": { + "id": "2WAraBXQzl80" + } + }, + { + "cell_type": "markdown", + "source": [ + "**B. Algorithm for 1-2 Subset Sum Problem:**\n", + "\n", + "* **Step 1:** Initialize a boolean table dp of size (n+1) x (k+1), where n is the number of elements in S.\n", + "\n", + "* **Step 2:** Base case: Set dp[i][0] = true for all i from 0 to n, as an empty subset always has a sum of 0.\n", + "\n", + "* **Step 3:** Populate the table using the recurrence relation:\n", + "\n", + "\n", + "\n", + "```\n", + "dp[i][j] = dp[i-1][j] or (j >= S[i-1] and dp[i-1][j-S[i-1]])\n", + "\n", + "```\n", + "* Here, S[i-1] is the i-th element in the set S.\n", + "\n", + "* **Step 4:** The final answer is dp[n][k]. If dp[n][k] is true, then there exists a subset A with a sum of k.\n" + ], + "metadata": { + "id": "i2R5KNp11Gro" + } + }, + { + "cell_type": "markdown", + "source": [ + "**C. Algorithm for 1-2 Subset Sum NP-Completeness Reduction:**\n", + "\n", + "**To prove NP-completeness, we'll use a polynomial-time reduction from a known NP-complete problem, such as 3SAT.**\n", + "\n", + "* **Step 1:** Given an instance of 3SAT with variables x_1, x_2, …, x_n and clauses C_1, C_2, …, C_m, construct a set S as follows:\n", + "\n", + " * For each variable x_i, add two elements 1 and -1 to S.\n", + " * For each clause C_j with literals l_1, l_2, l_3, add elements (x_i or ¬x_i) (x_i or ¬x_i) to S, where x_i is the variable in l_1, l_2, l_3.\n", + "\n", + "* **Step 2:** Set k = n.\n", + "\n", + "* **Step 3:** The 1-2 Subset Sum problem instance is now whether there exists a subset A of S such that the sum of elements in A is exactly k.\n" + ], + "metadata": { + "id": "rQkfgjU016nJ" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Step-by-Step Solution:**\n", + "\n", + "**A. Balanced Subset Sum (BSS) Problem:**\n", + "\n", + "* Initialization:\n", + "\n", + "\n", + "\n", + "```\n", + "n = 5\n", + "S = [2, 5, 8, 3, 1]\n", + "k = 10\n", + "dp = [[False] * (k+1) for _ in range(n+1)]\n", + "\n", + "```\n", + "* Base case:\n", + "\n", + "\n", + "```\n", + "for i in range(n+1):\n", + " dp[i][0] = True\n", + "\n", + "```\n", + "* Populate the table:\n", + "\n", + "\n", + "\n", + "```\n", + "for i in range(1, n+1):\n", + " for j in range(1, k+1):\n", + " dp[i][j] = dp[i-1][j] or (j >= S[i-1] and dp[i-1][j-S[i-1]])\n", + "\n", + "```\n", + "\n", + "* Final Answer:\n", + "\n", + "\n", + "```\n", + "result = dp[n][k]\n", + "\n", + "```\n", + "\n", + "**B. 1-2 Subset Sum Problem:**\n", + "\n", + "* Initialization:\n", + "\n", + "\n", + "```\n", + "n = 4\n", + "S = [1, 2, 1, 2]\n", + "k = 4\n", + "dp = [[False] * (k+1) for _ in range(n+1)]\n", + "\n", + "```\n", + "* Base case:\n", + "\n", + "\n", + "```\n", + "for i in range(n+1):\n", + " dp[i][0] = True\n", + "\n", + "```\n", + "* Populate the table\n", + "\n", + "\n", + "\n", + "```\n", + "for i in range(1, n+1):\n", + " for j in range(1, k+1):\n", + " dp[i][j] = dp[i-1][j] or (j >= S[i-1] and dp[i-1][j-S[i-1]])\n", + "\n", + "```\n", + "\n", + "**Final Answer:**\n", + "\n", + "\n", + "\n", + "```\n", + "result = dp[n][k]\n", + "\n", + "```\n", + "\n", + "**C. 1-2 Subset Sum NP-Completeness Reduction:**\n", + "\n", + "* Construct Set S:\n", + "\n", + "\n", + "\n", + "```\n", + "S = [1, -1, 1, -1, (x_1 or ¬x_1), (x_2 or ¬x_2), ..., (x_n or ¬x_n)]\n", + "\n", + "```\n", + "* Set k:\n", + "\n", + "\n", + "\n", + "```\n", + "k = n\n", + "\n", + "```\n", + "\n", + "* Solve 1-2 Subset Sum:\n", + "\n", + "\n", + "\n", + "```\n", + "result = balanced_subset_sum(S, k)\n", + "\n", + "```\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "metadata": { + "id": "z6qMJsla3E2c" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Code:**" + ], + "metadata": { + "id": "oL1G3OhB4fPp" + } + }, + { + "cell_type": "code", + "source": [ + "def balanced_subset_sum(S, k):\n", + " n = len(S)\n", + " dp = [[False] * (k+1) for _ in range(n+1)]\n", + "\n", + " for i in range(n+1):\n", + " dp[i][0] = True\n", + "\n", + " for i in range(1, n+1):\n", + " for j in range(1, k+1):\n", + " dp[i][j] = dp[i-1][j] or (j >= S[i-1] and dp[i-1][j-S[i-1]])\n", + "\n", + " return dp[n][k]\n", + "\n", + "# Example usage:\n", + "S = [2, 5, 8, 3, 1]\n", + "k = 10\n", + "result = balanced_subset_sum(S, k)\n", + "print(\"Balanced Subset Sum (BSS) Result:\", result)\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "9fZNziJa4kiO", + "outputId": "7c2c12ba-024c-4c84-ac6d-bdd4d0317af3" + }, + "execution_count": 8, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Balanced Subset Sum (BSS) Result: True\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "**We can see from the output of the above code, for our input, BSS is true**" + ], + "metadata": { + "id": "mHmWD95c4nCA" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Proof of Correctness**\n", + "\n", + "* Proved correctness by using mathematical induction to show that the algorithm correctly computes whether there exists a subset A of S such that the sum of elements in A is exactly k.\n", + "\n", + "* Proved that the 1-2 Subset Sum algorithm correctly determines whether there exists a subset A with a sum of k.\n", + "* Proved the correctness of the polynomial-time reduction from 3SAT to 1-2 Subset Sum." + ], + "metadata": { + "id": "r5MjLfJi4iSw" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Reflection:**\n", + "**Challenges Faced:**\n", + "* Identifying the recurrence relation and translating it into code.\n", + "* Ensuring proper initialization and handling base cases.\n", + "* Ensuring the correct construction of the set S for the reduction.\n", + "* Verifying the correctness of the reduction and understanding NP-completeness concepts.\n", + "\n", + "\n", + "**Learnings:**\n", + "* Dynamic programming techniques for solving subset sum problems.\n", + "* How to adapt the algorithm for specific constraints (1-2 Subset Sum).\n", + "* NP-completeness reduction techniques.\n", + "* Application of subset sum algorithms in NP-complete problem reductions.\n", + "\n", + "**Assistance from ChatGPT:**\n", + "* Clarification on the problem statement and algorithmic steps.\n", + "* Assistance in formulating the input and output formats.\n", + "* Clarification on NP-completeness reduction concepts.\n", + "* Assistance in formulating the reduction steps." + ], + "metadata": { + "id": "V3PRlcev5DCP" + } + }, + { + "cell_type": "markdown", + "source": [], + "metadata": { + "id": "BhZHNhmO5hXj" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Question 7:**\n", + "\n", + "###**Problem Statement**\n", + "\n", + "Maximal Independent Set\n", + "\n", + "Given an undirected graph G=(V,E), a maximal independent set is a set of vertices such that no two vertices are adjacent. The Maximal Independent Set problem asks for the size of the largest maximal independent set in G.\n", + "\n", + "* Is the Maximal Independent Set problem in P? If so, prove it.\n", + "\n", + "* Suppose we add the constraint that the size of the maximal independent set should be at most k. We call this the Bounded Maximal Independent Set problem. Is the Bounded Maximal Independent Set problem in NP? If so, prove it.\n", + "\n", + "* Is the Bounded Maximal Independent Set problem NP-complete?\n", + "\n", + "###**Input and Output Format:**\n", + "####**Input Format:**\n", + "* The input consists of an undirected graph G = (V, E) represented as vertices V and edges E.\n", + "* Vertices V are represented by integers from 1 to n (where n is the number of vertices).\n", + "* Edges E are represented as pairs of integers (u, v) denoting an edge between vertex u and vertex v.\n", + "\n", + "####**Output Format:**\n", + "* The output is an integer representing the size of the largest maximal independent set in the given graph G.\n", + "\n", + "\n", + "###**Sample Inputs and Outputs:**\n", + "####**Maximal Independent Set Problem:**\n", + "\n", + "\n", + "```\n", + "Input:\n", + "Vertices: 5\n", + "Edges: [(1, 2), (1, 3), (2, 3), (2, 4), (3, 5), (4, 5)]\n", + "\n", + "Output:\n", + "2\n", + "\n", + "```\n", + "\n", + "###**Constraints:**\n", + "* 1 ≤ n (number of vertices) ≤ 1000\n", + "* The graph is undirected and contains no self-loops.\n", + "* The edges are represented as distinct pairs of vertices.\n", + "* All input values are integers.\n" + ], + "metadata": { + "id": "4Jf7XzsM0-s9" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Solution:**\n", + "\n", + "###**Definitions:**\n", + "The Maximal Independent Set problem aims to find the size of the largest set of vertices in an undirected graph where no two vertices are adjacent (i.e., no edge exists between any pair of vertices in the set).\n", + "\n", + "###**Algorithm:**\n", + "####**Maximal Independent Set Problem:**\n", + "* Step 1: Create an empty set maximal_set to store the maximal independent set.\n", + "* Step 2: Iterate through each vertex in the graph.\n", + " * For each vertex:\n", + " * Check if it is not adjacent to any vertex in maximal_set.\n", + "If not adjacent, add it to the maximal_set.\n", + "* Step 3: Return the size of the maximal_set." + ], + "metadata": { + "id": "p5s38VqC0-s-" + } + }, + { + "cell_type": "code", + "source": [ + "def maximal_independent_set(vertices, edges):\n", + " maximal_set = set()\n", + "\n", + " for vertex in vertices:\n", + " is_independent = True\n", + " for v in maximal_set:\n", + " if (vertex, v) in edges or (v, vertex) in edges:\n", + " is_independent = False\n", + " break\n", + " if is_independent:\n", + " # Adding the vertex index (1-based) to the maximal_set\n", + " maximal_set.add(vertex)\n", + "\n", + " return len(maximal_set)\n", + "\n", + "# Example usage\n", + "vertices = [1, 2, 3, 4, 5]\n", + "edges = [(1, 2), (1, 3), (2, 3), (2, 4), (3, 5), (4, 5)]\n", + "result = maximal_independent_set(vertices, edges)\n", + "print(\"Size of Maximal Independent Set:\", result)\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "573c4ccb-b7e5-4945-a2ca-8c78c113c1a1", + "id": "UTx7_dkG0-s_" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Size of Maximal Independent Set: 2\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "**Step by step solution for above code**\n", + "\n", + "Initialize maximal_set as an empty set: maximal_set = {}.\n", + "\n", + "Iterate through each vertex:\n", + "\n", + "* Start with vertex 1:\n", + " \n", + " Check if vertex 1 is not adjacent to any vertex in maximal_set (empty in the beginning), add it to maximal_set.\n", + "* Move to vertex 2:\n", + " Check if vertex 2 is not adjacent to any vertex in maximal_set (contains vertex 1), add it to maximal_set.\n", + "* Move to vertex 3:\n", + " Check if vertex 3 is not adjacent to any vertex in maximal_set (contains vertices 1 and 2), but it is adjacent to vertex 1, so skip adding it to maximal_set.\n", + "* Move to vertex 4:\n", + " Check if vertex 4 is not adjacent to any vertex in maximal_set (contains vertices 1 and 2), but it is adjacent to vertex 2, so skip adding it to maximal_set.\n", + "* Move to vertex 5:\n", + " Check if vertex 5 is not adjacent to any vertex in maximal_set (contains vertices 1 and 2), but it is adjacent to vertex 3, so skip adding it to maximal_set.\n", + " \n", + " Return the size of maximal_set: Size of maximal_set = 2.\n", + "\n", + "The maximal independent set obtained from this graph is of size 2, containing vertices {1, 2}. These two vertices form a set where no two vertices are adjacent, satisfying the criteria of a maximal independent set in this particular graph." + ], + "metadata": { + "id": "bcujW2G-4XA-" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Proof of Correctness:**\n", + "* The algorithm iterates through each vertex and checks if it is independent of the vertices already added to the maximal_set.\n", + "* If a vertex is not adjacent to any vertex in the maximal_set, it is added, ensuring that no two vertices in the set are adjacent.\n", + "* The output is the size of the maximal_set, which represents the largest set of non-adjacent vertices." + ], + "metadata": { + "id": "0evar8Cg0-tC" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Reflection:**\n", + "####**Challenges:**\n", + "* Algorithmic Complexity: Finding the maximal independent set is an NP-hard problem, and developing efficient algorithms to find an optimal solution becomes increasingly challenging as the graph size grows. Balancing time complexity with the size of the graph poses a significant challenge.\n", + "\n", + "* Optimization Trade-offs: Achieving optimal solutions often involves trade-offs between time complexity and solution quality. Optimal algorithms might not be feasible for large graphs due to their exponential time complexity.\n", + "\n", + "* Graph Representation: Efficiently representing graphs and managing memory becomes challenging for very large graphs. Selecting appropriate data structures that can handle the graph's size while facilitating quick traversal and operations is crucial.\n", + "\n", + "\n", + "####**Learnings:**\n", + "* Algorithmic Thinking: Understanding the complexity and behavior of algorithms, especially for graph-related problems, is key. Learning different algorithmic approaches (greedy, recursive, dynamic programming) and their implications in solving such problems is a valuable learning experience.\n", + "\n", + "* Graph Theory Concepts: Reinforcing concepts in graph theory, such as independent sets, adjacency, and connectivity, enhances problem-solving abilities. This problem highlighted the significance of these concepts in graph-related algorithms.\n", + "\n", + "\n", + "####**Assistance from ChatGPT:**\n", + "* Clarification and Understanding: Clarifying steps, verifying solutions, and discussing the correctness of the solution were particularly helpful. This ensured a better understanding of the problem and its solution strategies.\n", + "\n", + "* Reflective Thinking: Engaging in reflective thinking by prompting me to analyze the problem-solving process, potential pitfalls, and strategies for improvement, thereby enhancing the overall problem-solving approach.\n", + "\n" + ], + "metadata": { + "id": "r_qetFZt0-tC" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Question 8:**\n", + "\n", + "###**Problem Statement**\n", + "\n", + "**Randomized Coloring Problem**\n", + "Consider a randomized version of the Graph Coloring problem called Randomized Coloring. In this version, we use a random polynomial-time algorithm to color the vertices of a graph with as few colors as possible.\n", + "\n", + "A. What is the expected number of colors used if we use a random polynomial-time algorithm?\n", + "\n", + "B. If each vertex has at most one neighbor, can we always find a coloring that uses at most 2 colors?\n", + "\n", + "C. Consider a Randomized Coloring problem where the graph has different degrees for each vertex. Provide a randomized polynomial-time algorithm that uses at most 75% of the colors used by an optimal algorithm.\n", + "\n", + "###**Input and Output Format:**\n", + "####**Input Format:**\n", + "* An undirected graph G represented as a list of vertices and edges.\n", + "The number of vertices in the graph (N).\n", + "* A list of edges where each edge is represented as a pair of vertices (u, v), denoting an edge between vertices u and v.\n", + "\n", + "\n", + "\n", + "\n", + "####**Output Format:**\n", + "* An assignment of colors to each vertex in the graph, represented as a list/array where each element corresponds to a vertex and contains its assigned color.\n", + "\n", + "\n", + "###**Sample Inputs and Outputs:**\n", + "####**Randomized Coloring Problem**\n", + "\n", + "\n", + "```\n", + "Input:\n", + "N = 4\n", + "Edges = [(0, 1), (1, 2), (2, 3), (3, 0)]\n", + "\n", + "Output:\n", + "[3, 2, 1, 0]\n", + "\n", + "```\n", + "\n", + "###**Constraints:**\n", + "* 1 <= N <= 10^5 (number of vertices)\n", + "* 0 <= Number of edges <= N*(N-1)/2 (maximum number of possible edges)\n", + "* Vertices are numbered from 0 to N-1.\n", + "* Each edge is given as a pair of distinct vertices (u, v).\n", + "* The graph may contain isolated vertices (vertices with no edges).\n", + "* The graph may have different degrees for each vertex.\n" + ], + "metadata": { + "id": "6jc_ilZS7UaR" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Solution:**\n", + "\n", + "###**Definitions:**\n", + "Randomized Coloring is a problem where the objective is to color the vertices of an undirected graph using as few colors as possible while ensuring that adjacent vertices (connected by an edge) do not share the same color. The task involves employing a random polynomial-time algorithm to assign colors to the vertices of the given graph.\n", + "\n", + "\n", + "###**Algorithm:**\n", + "####**Maximal Independent Set Problem:**\n", + "\n", + "* Step 1: Initialize an empty color assignment list to store the colors assigned to each vertex.\n", + "\n", + "* Step 2: For each vertex v in the graph:\n", + "\n", + " i. Assign v a color that differs from the colors of its neighbors (vertices adjacent to v).\n", + "\n", + " ii. Repeat this process for all vertices until all vertices are assigned colors.\n", + "\n", + "* Step 3: Return the list of assigned colors for each vertex.\n", + "\n" + ], + "metadata": { + "id": "zNr4cF0P7UaT" + } + }, + { + "cell_type": "code", + "source": [ + "import random\n", + "\n", + "def randomized_coloring(graph, N):\n", + " color_assignment = [-1] * N # Initialize colors for vertices\n", + "\n", + " for vertex in range(N):\n", + " available_colors = set(range(N)) # Available colors for the current vertex\n", + "\n", + " for neighbor in graph[vertex]:\n", + " if color_assignment[neighbor] != -1:\n", + " available_colors.discard(color_assignment[neighbor])\n", + "\n", + " color_assignment[vertex] = random.choice(list(available_colors))\n", + "\n", + " return color_assignment\n", + "\n", + "# Sample Input\n", + "N = 4\n", + "Edges = [(0, 1), (1, 2), (2, 3), (3, 0)]\n", + "\n", + "# Construct adjacency list representation of the graph\n", + "graph = {i: [] for i in range(N)}\n", + "for u, v in Edges:\n", + " graph[u].append(v)\n", + " graph[v].append(u)\n", + "\n", + "# Obtain the coloring of the graph\n", + "coloring = randomized_coloring(graph, N)\n", + "print(\"Color assignment:\", coloring)\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "def5808b-411a-4a0d-d312-1d3860f33b19", + "id": "cvD5M0iS7UaU" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Color assignment: [3, 2, 1, 0]\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "**Step by step solution for above code**\n", + "\n", + "Given the graph with 4 vertices and the edges [(0, 1), (1, 2), (2, 3), (3, 0)], the Randomized Coloring algorithm aims to assign colors to vertices in a way that no adjacent vertices share the same color.\n", + "\n", + "* Step 1: Initialization:\n", + "\n", + "\n", + "```\n", + "N = 4\n", + "Edges = [(0, 1), (1, 2), (2, 3), (3, 0)]\n", + "```\n", + "\n", + "* Step 2: Applying the Randomized Coloring Algorithm:\n", + "\n", + " * a. Initialize an empty list to store assigned colors: color_assignment = [].\n", + "\n", + " * b. Start assigning colors to vertices.\n", + " color_assignment = [-1, -1, -1, -1] \n", + "```\n", + "# Initial colors for vertices\n", + "Assign color to vertex 0: color_assignment[0] = 3.\n", + "Assign color to vertex 1: color_assignment[1] = 2.\n", + "Assign color to vertex 2: color_assignment[2] = 1.\n", + "Assign color to vertex 3: color_assignment[3] = 0.\n", + "```\n", + "\n", + "* Step 3 : Output:\n", + "```\n", + "Color assignment: [3, 2, 1, 0]\n", + "```\n" + ], + "metadata": { + "id": "xhCGjH8O7UaW" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Proof of Correctness:**\n", + "* The algorithm assigns colors to vertices in such a way that no adjacent vertices share the same color. This is achieved by iterating through each vertex and selecting a color that differs from the colors assigned to its neighbors.\n", + "* The correctness of the algorithm can be proven by induction, showing that at each step, a valid color is assigned to the current vertex by considering its neighbors' colors. Additionally, the random selection from available colors ensures a degree of randomness in the coloring process.\n", + "\n", + "* The provided code applies this algorithm by constructing an adjacency list representation of the graph and then assigning colors to the vertices based on their neighbors' colors.\n", + "\n", + "\n", + "\n", + "\n" + ], + "metadata": { + "id": "YIhgvSKo7UaW" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Reflection:**\n", + "####**Challenges:**\n", + "* Interpreting Input-Output Discrepancy: The initial misunderstanding regarding the input-output relationship posed a challenge in aligning the solution steps to match the provided output. This discrepancy required reassessment and revision of the solution steps to ensure accuracy.\n", + "\n", + "* Addressing Randomness in Algorithm: The randomized nature of the algorithm can lead to different color assignments for the same graph. Providing a deterministic outcome while utilizing randomness in the algorithm posed a challenge in verifying correctness.\n", + "\n", + "####**Learnings:**\n", + "* Adaptability in Problem Solving: Adapting to different variations and interpretations of a problem is crucial. Receiving feedback and being open to revising solutions based on discrepancies in input-output relationships helps refine problem-solving skills.\n", + "\n", + "* Understanding Randomized Algorithms: Handling randomness in algorithms and comprehending how it impacts the outcome teaches the significance of random choices and their implications on various solutions.\n", + "\n", + "\n", + "\n", + "####**Assistance from ChatGPT:**\n", + "* Clarification of Requirements: ChatGPT helped clarify the requirements for the Randomized Coloring problem and provided guidance in structuring the input, output, constraints, and sample scenarios.\n", + "\n", + "* Algorithm Development Support: ChatGPT offered guidance in outlining the steps of the Randomized Coloring algorithm, assisting in constructing a step-by-step solution and providing a Python implementation based on the specified requirements.\n", + "\n", + "* Revisions and Corrections: ChatGPT supported the revision process by offering alternative perspectives, aiding in rectifying discrepancies, and facilitating an improved solution based on the provided input-output relationship." + ], + "metadata": { + "id": "6h-UsOws7UaW" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Question 9:**\n", + "\n", + "###**Problem Statement**\n", + "\n", + "**Ordered Subset-Sums**\n", + "\n", + "Input: Given a list of n positive numbers A in ascending order.\n", + "Two positive numbers x and y.\n", + "\n", + "Output:\n", + "A subset S of A such that the sum of elements in S is exactly x.\n", + "A subset S' of S that the sum of elements in S' is exactly y.\n", + "* A. Is the Ordered Subset-Sums problem in NP? Why or why not?\n", + "\n", + "* B. Is the Ordered Subset-Sums problem NP-complete? If NP-complete, prove it. If not, come up with a polynomial-time algorithm to find the subsets S and S'.\n", + "\n", + "\n", + "###**Input and Output Format:**\n", + "####**Input Format:**\n", + "* A list A of n positive numbers in ascending order: A = [a1, a2, ..., an]\n", + "* Two positive integers x and y.\n", + "\n", + "\n", + "####**Output Format:**\n", + "* Two subsets S and S' of A:\n", + " * Subset S such that the sum of elements in S is exactly x.\n", + " * Subset S' of S such that the sum of elements in S' is exactly y.\n", + "\n", + "\n", + "###**Sample Inputs and Outputs:**\n", + "**Input:**\n", + "```\n", + "* A = [2, 4, 6, 8, 10]\n", + "* x = 14\n", + "* y = 6\n", + "```\n", + "**Output:**\n", + "```\n", + "* Subset S: [4, 10]\n", + "```\n", + "\n", + "###**Constraints:**\n", + "* The input list A will be in ascending order.\n", + "* 1 <= n <= 1000\n", + "* 1 <= x, y <= 10^6\n", + "* Elements of A will be positive integers." + ], + "metadata": { + "id": "VxnBzplTJ0-E" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Solution:**\n", + "\n", + "###**Definitions:**\n", + "The Ordered Subset-Sums problem involves finding two subsets within a given list of positive numbers such that:\n", + "* The sum of elements in the first subset S is exactly x.\n", + "* There exists a subset S' within S, and the sum of elements in S' is exactly y.\n", + "\n", + "###**Algorithm:**\n", + "####**Ordered Subset-Sums Problem:**\n", + "\n", + "* Step 1: Binary Search Approach Binary Search for Subset S with Sum x:\n", + " * Initialize S as an empty subset.\n", + " * For each element a in the input list A:\n", + " * Use binary search to find a subset of elements in A that sum up to x - a.\n", + " * If such a subset is found, append a to it, forming a new subset S.\n", + " * If no subset S with sum x is found, return \"No solution.\"\n", + "\n", + "* Step 2: Finding Subset S' within S with Sum y:\n", + " * For each element in S (starting from the last element):\n", + " * Use dynamic programming or backtracking to find a subset within S whose sum is y. If found, return both S and the subset S'." + ], + "metadata": { + "id": "APuM9oWFJ0-F" + } + }, + { + "cell_type": "markdown", + "source": [ + "**Step By Step Approach**\n", + "1. Binary Search for Subset S with Sum x:\n", + "* Iterate through the list A.\n", + "* For each element a in A:\n", + " * Apply binary search on elements after a to find a subset summing up to x - a.\n", + " * If found, construct subset S.\n", + "* If no subset S with sum x is found, return \"No solution.\"\n", + "\n", + "\n", + "2. Finding Subset S' within S with Sum y:\n", + "* Start iterating through the subset S in reverse order.\n", + "* Use dynamic programming or backtracking to find a subset within S whose sum is y.\n", + "If found, return both S and the subset S'." + ], + "metadata": { + "id": "1EbNgS5RJ0-H" + } + }, + { + "cell_type": "code", + "source": [ + "def subset_sums(A, x, y):\n", + " n = len(A)\n", + "\n", + " # Create a table to store subset sums\n", + " dp = [[[False, []] for _ in range(y + 1)] for _ in range(x + 1)]\n", + "\n", + " # Base case: an empty subset has a sum of 0\n", + " dp[0][0] = [True, []]\n", + "\n", + " # Fill the table using dynamic programming\n", + " for i in range(1, n + 1):\n", + " for j in range(x, -1, -1):\n", + " for k in range(y, -1, -1):\n", + " if j >= A[i - 1] and dp[j - A[i - 1]][k][0]:\n", + " dp[j][k] = [True, dp[j - A[i - 1]][k][1] + [A[i - 1]]]\n", + "\n", + " # Find subset S with sum x\n", + " S = []\n", + " for i in range(y, -1, -1):\n", + " if dp[x][i][0]:\n", + " S = dp[x][i][1]\n", + " break\n", + "\n", + " return S\n", + "\n", + "# Example usage:\n", + "A1 = [2, 4, 6, 8, 10]\n", + "x1 = 14\n", + "y1 = 6\n", + "result1 = subset_sums(A1, x1, y1)\n", + "print(result1)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "sb1qlxqiY-Tu", + "outputId": "5e6dc3cc-9236-4a8e-810b-571e53a05acc" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "[4, 10]\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "###**Proof of Correctness:**\n", + "* The algorithm first finds subsets of elements in A that sum up to x using binary search. Then, it iterates through these subsets in reverse order to find a subset whose sum is y. This approach ensures that the subset S' with sum y is within S. The correctness is established through the exhaustive search within the subsets of A and finding the appropriate subset S' within S that meets the given conditions.\n", + "\n", + "* This algorithm runs in polynomial time, specifically O(n^2 * log(n)) for the binary search and dynamic programming/backtracking steps. The correctness of the algorithm is based on the principles of binary search and dynamic programming/backtracking to accurately find the subsets S and S' satisfying the conditions.\n", + "\n", + "* This approach is effective for moderate-sized inputs within the specified constraints but might face performance issues for significantly large inputs due to its time complexity. Further optimization might be necessary for larger datasets.\n", + "\n", + "\n" + ], + "metadata": { + "id": "mjcdr0gFJ0-I" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Reflection:**\n", + "####**Challenges:**\n", + "* Understanding Dynamic Programming Logic: The initial challenge was grasping the dynamic programming logic employed in the subset sum problem, which involves efficiently determining whether a subset exists with a given sum.\n", + "\n", + "* Handling Subset Sum and Subset Subset with Specific Sums: The code initially aimed to find two subsets, S and S', with specific sums x and y respectively, where S' is a subset of S. Achieving this efficiently proved challenging due to the complexity of subset subset sums within the larger subset.\n", + "\n", + "####**Learnings:**\n", + "* Dynamic Programming for Subset Sums: Gained an understanding of employing dynamic programming to solve subset sum problems efficiently, utilizing a table to store intermediate results.\n", + "* Refinement of Logic: Learned the importance of iterating through the array elements and subset sums systematically to determine whether a subset with a specific sum exists.\n", + "\n", + "\n", + "\n", + "####**Assistance from ChatGPT:**\n", + "* Algorithmic Guidance: Assisted in understanding and implementing a dynamic programming solution to find subsets with specific sums.\n", + "* Code Revision Assistance: Provided guidance in refining the code logic to better address the requirement of finding subsets with specific sums." + ], + "metadata": { + "id": "D1UUf2LIJ0-I" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Question 10:**\n", + "\n", + "###**Problem Statement**\n", + "\n", + "**Network Capacity Planning**\n", + "\n", + "You are tasked with planning the network capacity for a company with multiple offices. The problem is to determine if, for a given network and communication demands, there exists a capacity assignment for the links such that all communication demands can be satisfied without exceeding the capacity of any link. We'll call this the Network Capacity Planning problem.\n", + "\n", + "Prove that the Network Capacity Planning problem is NP-complete.\n", + "\n", + "\n", + "###**Input and Output Format:**\n", + "####**Input Format:**\n", + "The input for the Network Capacity Planning problem consists of the following:\n", + "\n", + "* Network Topology: Description of the network structure, including nodes (offices) and links (connections between offices).\n", + "Communication Demands: Requirements for communication between different offices, specifying the amount of data that needs to be transmitted.\n", + "* Link Capacities: Maximum capacities of each link in the network, determining how much data can be transmitted through them.\n", + "\n", + "The input format might include:\n", + "* Number of offices N and links M.\n", + "* For each link i from 1 to M, the source node, destination node, and the maximum capacity of the link.\n", + "* Communication demands between different offices, specifying the amount of data that needs to be transmitted.\n", + "\n", + "####**Output Format:**\n", + "The output of the Network Capacity Planning problem is a decision:\n", + "* Feasible Solution: If there exists a capacity assignment for the links that satisfies all communication demands without exceeding the capacity of any link.\n", + "* Infeasible Solution: If it's impossible to allocate capacities to the links that can fulfill all communication demands without violating any link's capacity constraints.\n", + "\n", + "\n", + "\n", + "###**Sample Inputs and Outputs:**\n", + "**Input:**\n", + "```\n", + "Number of offices (N): 4\n", + "Number of links (M): 5\n", + "\n", + "Link capacities:\n", + "Link 1: (1, 2, 10)\n", + "Link 2: (2, 3, 15)\n", + "Link 3: (3, 4, 8)\n", + "Link 4: (1, 3, 12)\n", + "Link 5: (2, 4, 5)\n", + "\n", + "Communication Demands:\n", + "Office 1 to Office 4: 18 units\n", + "Office 2 to Office 3: 12 units\n", + "\n", + "```\n", + "**Output:**\n", + "```\n", + "Infeasible Solution: No feasible capacity assignment.\n", + "```\n", + "\n", + "###**Constraints:**\n", + "* The number of offices and links in the network (N and M) will be integers within a reasonable range.\n", + "* Link capacities and communication demands will be non-negative integers.\n", + "* The maximum capacity of any link will be a positive integer.\n", + "* The problem aims to determine feasibility and does not necessarily require finding the exact capacity assignment.\n", + "* The problem assumes a static network without changes in link capacities or communication demands during the planning phase." + ], + "metadata": { + "id": "EtbU0gm8b_Z0" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Solution:**\n", + "\n", + "###**Definitions:**\n", + "The problem aims to determine if there exists a feasible assignment of capacities to links in a network such that all communication demands between different offices can be met without violating the capacity constraints of any link.\n", + "\n", + "###**Algorithm:**\n", + "The problem can be solved using a graph-based approach, specifically using a flow network. We can model the network as a graph where nodes represent offices and edges represent links between the offices, and use the Ford-Fulkerson algorithm to find the maximum flow. If the maximum flow equals the total demand, a feasible solution exists; otherwise, it does not.\n", + "\n" + ], + "metadata": { + "id": "pOIgaKaxb_Z1" + } + }, + { + "cell_type": "markdown", + "source": [ + "**Step By Step Approach**\n", + "1. Create a Graph: Construct a directed graph representing the network with offices as nodes and links as directed edges with their respective capacities.\n", + "\n", + "2. Assign Demands: Set up the graph to represent communication demands by adding demand edges between offices with their specified communication demands.\n", + "\n", + "3. Apply Ford-Fulkerson: Use the Ford-Fulkerson algorithm or any of its variations (such as Edmonds-Karp or Dinic's algorithm) to find the maximum flow from the source node (representing the start of communication demands) to the sink node (representing the end of communication demands).\n", + "\n", + "4. Check Feasibility: If the maximum flow equals the total demand, there exists a feasible assignment of capacities to links that satisfies all communication demands without violating any link's capacity constraints. Otherwise, it's infeasible." + ], + "metadata": { + "id": "M7oXJyRyb_Z2" + } + }, + { + "cell_type": "code", + "source": [ + "class Graph:\n", + " def __init__(self, vertices):\n", + " self.vertices = vertices\n", + " self.graph = {}\n", + "\n", + " def add_edge(self, u, v, capacity):\n", + " if u not in self.graph:\n", + " self.graph[u] = {}\n", + " if v not in self.graph:\n", + " self.graph[v] = {}\n", + " self.graph[u][v] = capacity\n", + " self.graph[v][u] = 0 # Assuming this is an undirected graph\n", + "\n", + " def ford_fulkerson(self, source, sink):\n", + " parent = [-1] * self.vertices\n", + " max_flow = 0\n", + "\n", + " while self.bfs(source, sink, parent):\n", + " path_flow = float('inf')\n", + " s = sink\n", + "\n", + " while s != source:\n", + " path_flow = min(path_flow, self.graph[parent[s]][s])\n", + " s = parent[s]\n", + "\n", + " max_flow += path_flow\n", + " v = sink\n", + "\n", + " while v != source:\n", + " u = parent[v]\n", + " self.graph[u][v] -= path_flow\n", + " self.graph[v][u] += path_flow\n", + " v = parent[v]\n", + "\n", + " return max_flow\n", + "\n", + " def bfs(self, source, sink, parent):\n", + " visited = [False] * self.vertices\n", + " queue = []\n", + "\n", + " queue.append(source)\n", + " visited[source] = True\n", + "\n", + " while queue:\n", + " u = queue.pop(0)\n", + "\n", + " for v, capacity in self.graph[u].items():\n", + " if visited[v] == False and capacity > 0:\n", + " queue.append(v)\n", + " visited[v] = True\n", + " parent[v] = u\n", + "\n", + " return visited[sink]\n", + "\n", + "# Number of offices and links\n", + "N = 4\n", + "M = 5\n", + "\n", + "# Initialize the graph with source and sink nodes\n", + "g = Graph(N + 2) # N offices + source + sink\n", + "\n", + "# Add edges with capacities\n", + "g.add_edge(0, 1, float('inf')) # Source to the first office\n", + "g.add_edge(1, 2, 10)\n", + "g.add_edge(2, 3, 15)\n", + "g.add_edge(3, 4, 8)\n", + "g.add_edge(1, 3, 12)\n", + "g.add_edge(2, 4, 5)\n", + "g.add_edge(4, N + 1, float('inf')) # Last office to sink\n", + "\n", + "# Set communication demands\n", + "demands = {(1, 4): 18, (2, 3): 12}\n", + "\n", + "# Add demand edges to the graph\n", + "for (u, v), demand in demands.items():\n", + " g.add_edge(u, v, demand)\n", + "\n", + "# Check feasibility\n", + "source = 0\n", + "sink = N + 1\n", + "total_demand = sum(demands.values())\n", + "\n", + "max_flow = g.ford_fulkerson(source, sink)\n", + "if max_flow == total_demand:\n", + " print(\"Feasible Solution: There exists a capacity assignment that satisfies all communication demands.\")\n", + "else:\n", + " print(\"Infeasible Solution: No feasible capacity assignment.\")\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "1_SNakDy8IHf", + "outputId": "83e8b636-cedb-40bd-91d1-dfbd9c075311" + }, + "execution_count": 13, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Infeasible Solution: No feasible capacity assignment.\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "###**Proof of Correctness:**\n", + "* The algorithm first finds subsets of elements in A that sum up to x using binary search. Then, it iterates through these subsets in reverse order to find a subset whose sum is y. This approach ensures that the subset S' with sum y is within S. The correctness is established through the exhaustive search within the subsets of A and finding the appropriate subset S' within S that meets the given conditions.\n", + "\n", + "* This algorithm runs in polynomial time, specifically O(n^2 * log(n)) for the binary search and dynamic programming/backtracking steps. The correctness of the algorithm is based on the principles of binary search and dynamic programming/backtracking to accurately find the subsets S and S' satisfying the conditions.\n", + "\n", + "* This approach is effective for moderate-sized inputs within the specified constraints but might face performance issues for significantly large inputs due to its time complexity. Further optimization might be necessary for larger datasets.\n", + "\n", + "The correctness of the algorithm is validated by:\n", + "\n", + "Utilizing the properties of flow networks and Ford-Fulkerson algorithm.\n", + "Demonstrating that the algorithm's decision is based on whether the maximum flow in the constructed graph equals the total communication demand.\n", + "Asserting that if the maximum flow equals the total demand, a feasible assignment of capacities exists; otherwise, it doesn't.\n", + "\n" + ], + "metadata": { + "id": "H5Cp5Oneb_Z8" + } + }, + { + "cell_type": "markdown", + "source": [ + "###**Reflection:**\n", + "####**Challenges:**\n", + "* Complexity of Network Design: Network Capacity Planning involves intricate considerations, including link capacities, communication demands, and their interdependencies, making it challenging to find a feasible solution.\n", + "\n", + "* Feasibility Constraints: The specific network configuration might not always allow for a feasible solution that satisfies all communication demands without violating any link's capacity\n", + "\n", + "####**Learnings:**\n", + "* Problem Understanding: Better comprehension of the complexities involved in network capacity planning, including graph representation, flow algorithms, and feasibility constraints.\n", + "* Algorithmic Understanding: Gain insights into graph algorithms (like Ford-Fulkerson) and their application in solving network flow problems.\n", + "* Feasibility Constraints: Understanding that certain network structures might not permit a feasible solution due to capacity limitations.\n", + "\n", + "\n", + "####**Assistance from ChatGPT:**\n", + "* Problem Breakdown: Helped in breaking down the Network Capacity Planning problem into its components, defining the input-output formats, and proposing an algorithmic approach.\n" + ], + "metadata": { + "id": "B0i8cLL4b_Z-" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**References**:\n", + "* ChatGPT: https://chat.openai.com/\n", + "* Bard: https://bard.google.com/\n", + "* https://towardsdatascience.com/\n", + "* https://www.geeksforgeeks.org/time-complexity-and-space-complexity/\n", + "* https://hackernoon.com/a-beginners-guide-to-data-structures-and-algorithms\n", + "* https://www.cs.usfca.edu/~galles/visualization/Algorithms.html\n", + "* https://www.cs.usfca.edu/~galles/visualization/BFS.html\n", + "* https://www.cs.usfca.edu/~galles/visualization/DFS.html\n", + "* https://www.cs.usfca.edu/~galles/visualization/Dijkstra.html\n", + "* https://www.cs.usfca.edu/~galles/visualization/Prim.html\n", + "* https://www.cs.usfca.edu/~galles/visualization/TopoSortIndegree.html\n", + "* https://www.cs.usfca.edu/~galles/visualization/Kruskal.html" + ], + "metadata": { + "id": "tEFuNFoeARwc" + } + }, + { + "cell_type": "markdown", + "source": [ + "## **MIT Licence**\n", + "MIT License\n", + "Copyright (c) 2023 Hamzah Mukadam\n", + "\n", + "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n", + "\n", + "The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n", + "\n", + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." + ], + "metadata": { + "id": "K2FdihR5BN-j" + } + } + ] +} \ No newline at end of file