Compare commits
11 Commits
6a9630c5ac
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 0dab59e81e | |||
| d3e7ce3189 | |||
| c6c7e667c3 | |||
| 7739e18c7f | |||
| 38117921ed | |||
| 97e92b8b14 | |||
| a730e01e9c | |||
| 82ba7de3eb | |||
| e1b3928cf4 | |||
| 1ecef01de4 | |||
| ff22086802 |
79
Arbitrages/README.md
Normal file
79
Arbitrages/README.md
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
# Homework 6: Arbitrages
|
||||||
|
|
||||||
|
## Finding an Arbitrage
|
||||||
|
|
||||||
|
In currency exchange markets units of one currency, such as US Dollars, can be exchanged for units of a different currency, like Italian Lira. These exchanges are set by the market's exchange rate, which typically fluctuates throughout the day. For example, at the time of this assignment's writing, the exchange rate between the US Dollar (USD) and the Great British Pound (GBP) was 1 USD to 0.77 GBP. This means that $150 is worth $150\cdot0.77=115.5\ \text{GBP}$ and $150\ \text{GPB} = 150 / 0.77 = \$194.81$. The exchange rates are dynamic and constantly change.
|
||||||
|
|
||||||
|
This change in currency is based on how trades are progressing through the market, and the changing dynamic nature of the exchange leads to a particular inefficiency in short-time frame based trading. For example, consider the following exchange rates:
|
||||||
|
|
||||||
|
- 1 USD = 0.82 Euro
|
||||||
|
- 1 Euro = 129.7 Japanese Yen
|
||||||
|
- 1 Japanese Yen = 12 Turkish Lira
|
||||||
|
- 1 Turkish Lira = 0.0008 USD.
|
||||||
|
|
||||||
|
So if we start with 1 USD, and make all of the exchanges above, we get $1\cdot0.82\cdot129.7\cdot12\cdot.0008 = \$1.021$. In other words, by making four exchanges starting from $1.00 we end up with $1.02, a 2% profit. This situation, where a cycle of currency exchanges starting and ending in the same currency leads to a net gain in the starting currency (rather than breaking even) is called arbitrage.
|
||||||
|
|
||||||
|
Notice that arbitrage occurs when the product of all of the exchanges in a cycle is greater than 1. Your job is to find and detect arbitrage in a given exchange and determine what sequence of exchanges need to be made.
|
||||||
|
|
||||||
|
We are going to reduce this problem to the problem of finding negative weight cycles in a graph. There are two problems to overcome.
|
||||||
|
|
||||||
|
1. Our formulation of the problem requires a product of the exchange rates, but shortest path algorithms work with the sum of the weights of a bunch of edges.
|
||||||
|
2. Negative weight cycles are "smaller" whereas we are attempting to maximize a profit.
|
||||||
|
|
||||||
|
The first problem can be overcome using the following trick: the logarithm function is monotonic, which means that log(x) increases when x increases. Furthermore, the logarithm function can be used to convert products into sums because $\log(a\cdot{b}) = \log(a) + \log(b)$. Thus, if we want to maximize $a\cdot{b}$, this is the same as maximizing $\log(a) + \log(b)$. Also, consider that $a\cdot{b} > 1$ if and only if $\log(a) + \log(b) > 0$. Thus a cycle of exchange rates $r1\cdot{r2}\cdot{r3}\cdot...\cdot{rn} > 1$ if and only if $\log(r1) + \log(r2) + ... + \log(rn) > 0$.
|
||||||
|
|
||||||
|
But now the second problem is that we want to detect negative weight cycles because Bellman-Ford can do that for us, but above we described a positive weight cycle. Now we can use the following trick--simply negate each log value. $\log(r1) + \log(r2) + ... + \log(rn) > 0$ if and only if $(-\log(r1)) + (-\log(r2)) + ... + (-\log(rn)) < 0$. Now, you should be able to see how to build a graph, with some appropriate weights, and use it to find arbitrage cycles directly!
|
||||||
|
|
||||||
|
### Input
|
||||||
|
|
||||||
|
The first line of the input will contain a single integer m describing how many exchange rates are in the exchange. The next _m_ lines will be given by _cIn_ _cOut_ _r_ where _cIn_ is the code for the starting currency (like USD or GPB), _cOut_ is the code for the ending currency, and _r_ is the exchange rate (i.e. "USD GBP 0.75" codes for 1 USD = 0.75 GBP).
|
||||||
|
|
||||||
|
### Output and Rubrics
|
||||||
|
|
||||||
|
This assignment is worth 15 points.
|
||||||
|
|
||||||
|
- 9 points (partial) -- code identifies an the presence or absence of an arbitrage correctly on published test cases
|
||||||
|
- 3 points (partial) -- code identifies an the presence or absence of an arbitrage correctly on hidden test cases
|
||||||
|
- 2 points (full credit) -- code outputs the actual exchanges correctly and in the format specified on the public test cases
|
||||||
|
- 1 point (full credit) -- code outputs the actual exchanges correctly and in the format specified on the hidden test cases
|
||||||
|
|
||||||
|
For full credit, when an arbitrage is detected, in addition to the output above, your code should output the actual exchanges that need to be made by showing each currency code in the exchange separated by " => " on a second line, and a third line containing the actual change as a multiplicative factor with the format "X factor increase", which should be **formatted to 5 decimal points**.
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>Sample Input</td>
|
||||||
|
<td>Partial Credit Output</td>
|
||||||
|
<td>Full Credit Output</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><pre>
|
||||||
|
4
|
||||||
|
USD EUR 0.82
|
||||||
|
EUR JPY 129.7
|
||||||
|
JPY TRY 12
|
||||||
|
TRY USD 0.0008</pre></td>
|
||||||
|
<td><pre>Arbitrage Detected</pre></td>
|
||||||
|
<td><pre>
|
||||||
|
Arbitrage Detected
|
||||||
|
USD => EUR => JPY => TRY => USD
|
||||||
|
1.02100 factor increase</pre></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>Sample Input</td>
|
||||||
|
<td>Sample Output (for both partial and full credit options)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><pre>
|
||||||
|
2
|
||||||
|
USD GBP 1.0
|
||||||
|
GBP USD 1.0</pre></td>
|
||||||
|
<td><pre>No Arbitrage Detected</pre></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
### Submission
|
||||||
|
|
||||||
|
Submit this assignment as `cs412_arbitrages_a.py` to Gradescope.
|
||||||
83
Arbitrages/cs412_arbitrages_a.py
Normal file
83
Arbitrages/cs412_arbitrages_a.py
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
"""
|
||||||
|
name: Nicholas Tamassia
|
||||||
|
|
||||||
|
Honor Code and Acknowledgments:
|
||||||
|
|
||||||
|
This work complies with the JMU Honor Code.
|
||||||
|
|
||||||
|
Comments here on your code and submission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import math
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
|
||||||
|
def find_arbitrage(graph: dict[str, dict[str, float]]) -> list[str] | None:
|
||||||
|
weights: dict[str, float] = {c: math.inf for c in graph}
|
||||||
|
prev: dict[str, str | None] = {c: None for c in graph}
|
||||||
|
start: str = list(graph.keys())[0]
|
||||||
|
|
||||||
|
weights[start] = 0
|
||||||
|
for _ in range(len(graph) - 1):
|
||||||
|
for src in graph:
|
||||||
|
for dest, rate in graph[src].items():
|
||||||
|
weight: float = -math.log(rate)
|
||||||
|
if weights[src] + weight < weights[dest]:
|
||||||
|
weights[dest] = weights[src] + weight
|
||||||
|
prev[dest] = src
|
||||||
|
|
||||||
|
node: str | None = None
|
||||||
|
for src in graph:
|
||||||
|
for dest, rate in graph[src].items():
|
||||||
|
weight: float = -math.log(rate)
|
||||||
|
if weights[src] + weight < weights[dest]:
|
||||||
|
node = dest
|
||||||
|
prev[dest] = src
|
||||||
|
break
|
||||||
|
if node is not None:
|
||||||
|
break
|
||||||
|
|
||||||
|
if node is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
for _ in range(len(graph)):
|
||||||
|
node = prev[node]
|
||||||
|
|
||||||
|
path = [node]
|
||||||
|
while True:
|
||||||
|
node = prev[node]
|
||||||
|
path.append(node)
|
||||||
|
if node == path[0]:
|
||||||
|
break
|
||||||
|
|
||||||
|
path.reverse()
|
||||||
|
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
n: int = int(input().strip())
|
||||||
|
graph: dict[str, dict[str, float]] = defaultdict(dict)
|
||||||
|
|
||||||
|
for _ in range(n):
|
||||||
|
vals: list[str] = input().strip().split()
|
||||||
|
src: str = vals[0]
|
||||||
|
dest: str = vals[1]
|
||||||
|
rate: float = float(vals[2])
|
||||||
|
graph[src][dest] = rate
|
||||||
|
|
||||||
|
path = find_arbitrage(graph)
|
||||||
|
if path is not None:
|
||||||
|
print("Arbitrage Detected")
|
||||||
|
print(" => ".join(path))
|
||||||
|
|
||||||
|
factor = 1.0
|
||||||
|
for i in range(len(path) - 1):
|
||||||
|
factor *= graph[path[i]][path[i + 1]]
|
||||||
|
print(f"{factor:.5f} factor increase")
|
||||||
|
else:
|
||||||
|
print("No Arbitrage Detected")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
5
Arbitrages/inputs/sample1.txt
Normal file
5
Arbitrages/inputs/sample1.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
4
|
||||||
|
USD EUR 0.82
|
||||||
|
EUR JPY 129.7
|
||||||
|
JPY TRY 12
|
||||||
|
TRY USD 0.0008
|
||||||
3
Arbitrages/inputs/sample2.txt
Normal file
3
Arbitrages/inputs/sample2.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
2
|
||||||
|
USD GBP 1.0
|
||||||
|
GBP USD 1.0
|
||||||
104
Basic-Graphs/README.md
Normal file
104
Basic-Graphs/README.md
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
# Homework 5: Basic Graphs
|
||||||
|
|
||||||
|
## Preface
|
||||||
|
|
||||||
|
This problem comes directly from a CS 412 student's coding interview with
|
||||||
|
Amazon. The student was given one hour to solve three different problems and
|
||||||
|
this was one of the problems. The easiest way to solve this problem quickly with
|
||||||
|
a minimal amount of code is recursively, which is probably the right way to
|
||||||
|
knock something like this out under coding interview pressure. This is also a
|
||||||
|
very slight twist on a very standard coding interview question.
|
||||||
|
|
||||||
|
You only need to code up one implementation and turn it in and I don't care if
|
||||||
|
it's the iterative or the recursive solution; however, I suggest you take the
|
||||||
|
following approach to this problem:
|
||||||
|
|
||||||
|
1. Set aside one hour to approach this problem fresh and attempt to knock out a
|
||||||
|
complete solution to the problem on your first try in under an hour. You
|
||||||
|
haven't been practicing this sort of thing (that is, trying to code under a
|
||||||
|
strict time limit), so its likely that you won't succeed within the hour time
|
||||||
|
limit. The purpose of this exercise is for you go gauge where you are at.
|
||||||
|
2. Take your time in coding a solution. I suggest you code both a recursive
|
||||||
|
solution and an iterative solution. These are the sorts of things you should
|
||||||
|
be working to get comfortable with coding as second nature. Obviously, the
|
||||||
|
first time you code it, it will not be second nature yet. You have to do it a
|
||||||
|
lot before it becomes second nature. Practice, as always, makes perfect here.
|
||||||
|
As I always tell students: learning to code is much more like learning a
|
||||||
|
musical instrument than learning a body of facts. You only get better at what
|
||||||
|
you practice. Class time / instruction only exists to point you towards what
|
||||||
|
you need to do, but you have to go and do it.
|
||||||
|
3. Once you've coded solutions to the problem, on a different day, set aside
|
||||||
|
another hour for yourself and try to code a solution as quickly as possible
|
||||||
|
without referring to your previous solutions. You've now done the hard work
|
||||||
|
in step 2 of actually solving, coding, and debugging your first solution.
|
||||||
|
|
||||||
|
It's time to reinforce those neural pathways in your mind and make this sort of
|
||||||
|
problem a part of your repertoire--every professional cellist in the world can
|
||||||
|
play the prelude to Bach's cello suite in G without preparation (if you don't
|
||||||
|
know the piece, switch to Spotify, load up one of Yo-Yo Ma's recordings of it,
|
||||||
|
then come back here), every computer scientist should be able to bang out a
|
||||||
|
recursive solution to this problem without even thinking about it. But that only
|
||||||
|
comes with practice. I've coded variations of this probably hundreds of times at
|
||||||
|
this point, if not thousands, which is why I can live code it in class with you
|
||||||
|
without having to debug. Y'all are at the point where you have all the knowledge
|
||||||
|
you need and solidifying it practice is the final piece.
|
||||||
|
|
||||||
|
So, with Yo-Yo Ma playing Bach's Prelude to the Cello Suite in G in the
|
||||||
|
background try to rewrite your solution from scratch as quickly as possible.
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
|
||||||
|
You have been hired by an elite treasure hunting team to help them find a
|
||||||
|
treasure that was hidden on a large island in the South Pacific. The team has
|
||||||
|
obtained LIDAR scans of a large square patch of ocean and has preprocessed the
|
||||||
|
scans into an n x n array where each array slot is either a 0 or a 1. A 0
|
||||||
|
denotes ocean while a 1 denotes land. Each array slot corresponds to 1 acre of
|
||||||
|
scan and adjacent slots in the array (in the vertical or horizontal directions,
|
||||||
|
but not diagonal) that both contain a 1 are considered part of the same land
|
||||||
|
mass / island. Your task is to find the size of the largest island in acres.
|
||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
The input is given by a line containing a single number _n_ followed by n lines,
|
||||||
|
each of which has n values of either 0 or 1 separated by spaces representing the
|
||||||
|
scan of the region.
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
The output is a single number which is the size of the largest island in the map
|
||||||
|
in acres.
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>Sample Input</td>
|
||||||
|
<td>Sample Output</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><pre>
|
||||||
|
6
|
||||||
|
0 1 0 0 0 0
|
||||||
|
0 1 1 0 0 0
|
||||||
|
0 0 0 1 1 1
|
||||||
|
0 0 1 1 1 0
|
||||||
|
0 0 1 1 0 0
|
||||||
|
1 0 0 0 0 0</pre></td>
|
||||||
|
<td><pre>8</pre></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><pre>
|
||||||
|
8
|
||||||
|
0 1 0 0 0 0 1 1
|
||||||
|
0 1 1 0 0 1 1 0
|
||||||
|
0 0 0 1 1 1 1 1
|
||||||
|
0 0 1 1 1 0 1 1
|
||||||
|
0 0 1 1 0 1 1 0
|
||||||
|
1 0 0 0 0 0 1 1
|
||||||
|
0 0 0 0 0 1 1 0
|
||||||
|
0 0 0 0 0 0 1 1</pre></td>
|
||||||
|
<td><pre>24</pre></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
## Turning it in
|
||||||
|
|
||||||
|
Name your program `cs412_islands_a.py` and turn it in on Gradescope.
|
||||||
67
Basic-Graphs/cs412_islands_a.py
Normal file
67
Basic-Graphs/cs412_islands_a.py
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
"""
|
||||||
|
name: Nicholas Tamassia
|
||||||
|
|
||||||
|
Honor Code and Acknowledgments:
|
||||||
|
|
||||||
|
This work complies with the JMU Honor Code.
|
||||||
|
|
||||||
|
Comments here on your code and submission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def explore_island(grid: list[list[int]], start: tuple[int, int]) -> int:
|
||||||
|
num_rows: int = len(grid)
|
||||||
|
num_cols: int = len(grid[0])
|
||||||
|
size: int = 0
|
||||||
|
|
||||||
|
def recurse(coord: tuple[int, int]):
|
||||||
|
x, y = coord
|
||||||
|
|
||||||
|
if grid[y][x] == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
nonlocal size
|
||||||
|
size += 1
|
||||||
|
grid[y][x] = 0
|
||||||
|
|
||||||
|
if y > 0:
|
||||||
|
recurse((x, y - 1))
|
||||||
|
if y < num_rows - 1:
|
||||||
|
recurse((x, y + 1))
|
||||||
|
if x > 0:
|
||||||
|
recurse((x - 1, y))
|
||||||
|
if x < num_cols - 1:
|
||||||
|
recurse((x + 1, y))
|
||||||
|
|
||||||
|
recurse(start)
|
||||||
|
|
||||||
|
return size
|
||||||
|
|
||||||
|
|
||||||
|
# All modules for CS 412 must include a main method that allows it
|
||||||
|
# to imported and invoked from other python scripts
|
||||||
|
def main():
|
||||||
|
n: int = int(input())
|
||||||
|
|
||||||
|
land_grid: list[list[int]] = [list(map(int, input().split())) for _ in range(0, n)]
|
||||||
|
|
||||||
|
num_rows: int = n
|
||||||
|
num_cols: int = len(land_grid[0])
|
||||||
|
|
||||||
|
largest_island: int = -1
|
||||||
|
|
||||||
|
for y in range(0, num_rows):
|
||||||
|
for x in range(0, num_cols):
|
||||||
|
if land_grid[y][x] == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
island_size: int = explore_island(land_grid, (x, y))
|
||||||
|
|
||||||
|
if island_size > largest_island:
|
||||||
|
largest_island = island_size
|
||||||
|
|
||||||
|
print(largest_island)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
7
Basic-Graphs/inputs/sample1.txt
Normal file
7
Basic-Graphs/inputs/sample1.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
6
|
||||||
|
0 1 0 0 0 0
|
||||||
|
0 1 1 0 0 0
|
||||||
|
0 0 0 1 1 1
|
||||||
|
0 0 1 1 1 0
|
||||||
|
0 0 1 1 0 0
|
||||||
|
1 0 0 0 0 0
|
||||||
9
Basic-Graphs/inputs/sample2.txt
Normal file
9
Basic-Graphs/inputs/sample2.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
8
|
||||||
|
0 1 0 0 0 0 1 1
|
||||||
|
0 1 1 0 0 1 1 0
|
||||||
|
0 0 0 1 1 1 1 1
|
||||||
|
0 0 1 1 1 0 1 1
|
||||||
|
0 0 1 1 0 1 1 0
|
||||||
|
1 0 0 0 0 0 1 1
|
||||||
|
0 0 0 0 0 1 1 0
|
||||||
|
0 0 0 0 0 0 1 1
|
||||||
9
Basic-Graphs/inputs/sample3.txt
Normal file
9
Basic-Graphs/inputs/sample3.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
8
|
||||||
|
0 0 1 0 0 0 0 1 0 0 0 0 0
|
||||||
|
0 0 0 0 0 0 0 1 1 1 0 0 0
|
||||||
|
0 1 1 0 1 0 0 0 0 0 0 0 0
|
||||||
|
0 1 0 0 1 1 0 0 1 0 1 0 0
|
||||||
|
0 1 0 0 1 1 0 0 1 1 1 0 0
|
||||||
|
0 0 0 0 0 0 0 0 0 0 1 0 0
|
||||||
|
0 0 0 0 0 0 0 1 1 1 0 0 0
|
||||||
|
0 0 0 0 0 0 0 1 1 0 0 0 0
|
||||||
BIN
Graph-Search/assets/graph.png
Normal file
BIN
Graph-Search/assets/graph.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
55
Graph-Search/class-activity.md
Normal file
55
Graph-Search/class-activity.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# Class Activity: Exploring MST Characteristics
|
||||||
|
|
||||||
|
We will be exploring creating graphs that showcase different aspects of MST
|
||||||
|
algorithms.
|
||||||
|
|
||||||
|
## Task 1:
|
||||||
|
|
||||||
|
True/False. A MST can sometimes contain a cycle. Justify your answer with one or
|
||||||
|
two sentences.
|
||||||
|
|
||||||
|
> Answer: False. By definition you can remove an edge from cycle and all
|
||||||
|
> vertices will still be connected. Therefor if the MST has a cycle in it then
|
||||||
|
> that would mean it has a redundant edge and is therefore not minimal.
|
||||||
|
|
||||||
|
## Task 2:
|
||||||
|
|
||||||
|
For the following graph, show the safe data structure after one call to
|
||||||
|
Borůvka's `AddAllSafeEdges` method. Draw the spanning tree F showing all of the
|
||||||
|
safe edges that were added to it after this first pass.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Task 3:
|
||||||
|
|
||||||
|
Create a graph with at least 6 nodes that is fully connected (a complete graph)
|
||||||
|
and has distinct edge weights that Boruvka's algorithm can solve in a single
|
||||||
|
call to `AddAllSafeEdges`. Submit a picture of the graph and the safe array/list
|
||||||
|
that is created by the call to `AddAllSafeEdges`.
|
||||||
|
|
||||||
|
## Task 4:
|
||||||
|
|
||||||
|
Create a graph with at least 6 vertices with distinct edge weights such that the
|
||||||
|
MST contains the edge with the largest weight. Submit a picture of this graph.
|
||||||
|
|
||||||
|
## Task 5:
|
||||||
|
|
||||||
|
Create a graph with at least 4 nodes that is fully connected (a complete graph)
|
||||||
|
and has distinct edge weights that Boruvka's algorithm exhibits its worst case
|
||||||
|
performance. First, define what the worst case perform is for a single call to
|
||||||
|
`AddAllSafeEdges`. Next, showcase this performance on your graph clearly showing
|
||||||
|
how the MST (F) looks after a single call to `AddAllSafeEdges` and showing the
|
||||||
|
contents of the array/list **safe**.
|
||||||
|
|
||||||
|
## Task 6:
|
||||||
|
|
||||||
|
Can you create a graph with at least 4 vertices with distinct edge weights such
|
||||||
|
that the MST does not contain the lightest edge? Explain your answer both
|
||||||
|
logically (1 to 2 sentences) and using the logic within Boruvka's
|
||||||
|
`AddAllSafeEdges`.
|
||||||
|
|
||||||
|
## Submission
|
||||||
|
|
||||||
|
Submit a picture of your answers to this canvas assignment. If you worked with
|
||||||
|
another person, acknowledge that by placing the names of all people you worked
|
||||||
|
with at the top of the first page of your submission.
|
||||||
65
NP-Complete/README.md
Normal file
65
NP-Complete/README.md
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
# Lab 17: NP-Completeness
|
||||||
|
|
||||||
|
## NP-Complete Problems
|
||||||
|
|
||||||
|
### Part A: Unsatisfiable 3-SAT (3 points)
|
||||||
|
|
||||||
|
Answer the following questions:
|
||||||
|
|
||||||
|
- Given a 3SAT problem with 3 binary variables (x1, x2, and x3), what is the min number of clauses that you would need to create an unsatisfiable sentence?
|
||||||
|
- Create a 3SAT sentence with 3 binary variable that is not satisfiable using the minimum number of clauses identified in part 1.
|
||||||
|
|
||||||
|
Turn these in directly here in Canvas.
|
||||||
|
|
||||||
|
### Part B -- Python's Itertools (3 points)
|
||||||
|
|
||||||
|
Python provides a powerful package called itertools (see this webpage for details: [https://docs.python.org/3/library/itertools.html](https://docs.python.org/3/library/itertools.html)). This package provides an easy and memory efficient method of producing iterables that represent combination or permutations of items.
|
||||||
|
|
||||||
|
- Construct a python program that uses the itertools function to print out all possible assignments of a 3 boolean variables. You will need to use the product function within itertools. If you need more help with the product function, look up itertools' documentation on the web.
|
||||||
|
- Augment your python program so that it contains a function that accepts 3 variables (x1, x2, and x3). This function must return the truth value of the 3-SAT sentence you created in Part A:2 (should just be a return statement evaluating the expression). Call this function with all the possible settings and show that your sentence is indeed not satisfiable. In other words, if your function returns true, print the settings that produced a true answer, otherwise print a message verifying that it always returned false.
|
||||||
|
- Create another function that is a copy of the one created in #2 but is missing one of the 3-SAT clauses. Using a similar for loop to #2, call this function with all possible settings of the boolean variables and print out the case where it finds a true assignment (a satisfying assignment).
|
||||||
|
|
||||||
|
Attach this program to this assignment, call it: `cs412_np_3satcheck.py`
|
||||||
|
|
||||||
|
### Part C -- Practice Reduction (3 points)
|
||||||
|
|
||||||
|
Given the following 3-SAT sentence, construct the graph that would serve as input to the independent set problem.
|
||||||
|
|
||||||
|
$(a\lor{b}\lor{c})\land(\lnot{a}\lor{b}\lor{c})\land(a\lor\lnot{b}\lor{c})\land(\lnot{a}\lor\lnot{b}\lor\lnot{c})$
|
||||||
|
|
||||||
|
- Draw this graph on a piece of paper and take a picture of it (and attach it to this assignment).
|
||||||
|
- Write a brief (one sentence) description of the decision problem that needs to be solved by the independent set problem to show that this 3-SAT sentence has a valid assignment.
|
||||||
|
- Identify the largest independent set in the graph created in step #1. If you select the variable "a" that is in the first clause, write that down as A1 (where the one identifies the clause that the variable came from). You can write this on your piece of paper with the graph (just make sure it is included in the picture) OR you can write it in the response section in Canvas.
|
||||||
|
|
||||||
|
### Part D -- Prove that Independent Set is in NP (3 points)
|
||||||
|
|
||||||
|
Write a program that accepts a description of an undirected graph G and a list of vertices and verifies (in polynomial time) that the list of vertices is indeed an independent set).
|
||||||
|
|
||||||
|
Here is some example input:
|
||||||
|
|
||||||
|
```
|
||||||
|
4
|
||||||
|
0 1
|
||||||
|
1 0 3
|
||||||
|
2
|
||||||
|
3 1
|
||||||
|
0 3 2
|
||||||
|
```
|
||||||
|
|
||||||
|
The first line tells you how many vertices are in the graph G. The lines that follow contain the edge list for edge vertex. Finally, a proposed independent set is listed. Your program should output TRUE if the set listed in an independent set or FALSE if it is not an independent set (for example, 0 1 should not be an independent set).
|
||||||
|
|
||||||
|
Attached this program to this assignment and call it `cs412_np_independent_set.py`
|
||||||
|
|
||||||
|
### Part E -- Show that Hamiltonian Paths are NP-Complete (3 points)
|
||||||
|
|
||||||
|
In this section, you need to construct the required components to show that finding a Hamiltonian path is NP-Complete (there are 3 components). Illustrate the reduction sequence as we did on the slides (as a picture) and using the <=p syntax and the boxes. **Note: You do NOT need to show the steps required to change the input (the reduction), just the sketch of the order and what would need to be accomplished.** For the other steps, write a sentence or two and if necessary, argue that these steps can be accomplished in polynomial time.
|
||||||
|
|
||||||
|
Submit these items in a section labels Part E in your writeup.
|
||||||
|
|
||||||
|
### What and Where to Submit:
|
||||||
|
|
||||||
|
Submit the following 3 files here in Canvas:
|
||||||
|
|
||||||
|
- `cs412_np_3satcheck.py`
|
||||||
|
- `cs412_np_independent_set.py`
|
||||||
|
- `cs412_nplab.pdf`
|
||||||
51
NP-Complete/cs412_np_3satcheck.py
Normal file
51
NP-Complete/cs412_np_3satcheck.py
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
"""
|
||||||
|
name: Nicholas Tamassia
|
||||||
|
|
||||||
|
Honor Code and Acknowledgments:
|
||||||
|
|
||||||
|
This work complies with the JMU Honor Code.
|
||||||
|
|
||||||
|
Comments here on your code and submission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from itertools import product
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
|
type Three_SAT = Callable[[bool, bool, bool], bool]
|
||||||
|
|
||||||
|
|
||||||
|
def three_sat_missing(x1: bool, x2: bool, x3: bool) -> bool:
|
||||||
|
combos = product([x1, not x1], [x2, not x2], [x3, not x3])
|
||||||
|
# Remove the last clause
|
||||||
|
missing_combo = list(combos)[:-1]
|
||||||
|
return all(a or b or c for a, b, c in missing_combo)
|
||||||
|
|
||||||
|
|
||||||
|
def three_sat(x1: bool, x2: bool, x3: bool) -> bool:
|
||||||
|
return all(
|
||||||
|
a or b or c for a, b, c in product([x1, not x1], [x2, not x2], [x3, not x3])
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# All modules for CS 412 must include a main method that allows it
|
||||||
|
# to imported and invoked from other python scripts
|
||||||
|
def main():
|
||||||
|
settings = product([False, True], repeat=3)
|
||||||
|
|
||||||
|
sentences_satisfied: dict[Three_SAT, bool] = {}
|
||||||
|
sentences_satisfied[three_sat] = False
|
||||||
|
sentences_satisfied[three_sat_missing] = False
|
||||||
|
|
||||||
|
for setting in settings:
|
||||||
|
for sentence in sentences_satisfied:
|
||||||
|
if sentence(*setting):
|
||||||
|
print(f"{setting} satisfied {sentence.__name__}")
|
||||||
|
sentences_satisfied[sentence] = True
|
||||||
|
|
||||||
|
for sentence, satisfied in sentences_satisfied.items():
|
||||||
|
if not satisfied:
|
||||||
|
print(f"{sentence.__name__} is not satisfiable")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
38
NP-Complete/cs412_np_independent_set.py
Normal file
38
NP-Complete/cs412_np_independent_set.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
"""
|
||||||
|
name: Nicholas Tamassia
|
||||||
|
|
||||||
|
Honor Code and Acknowledgments:
|
||||||
|
|
||||||
|
This work complies with the JMU Honor Code.
|
||||||
|
|
||||||
|
Comments here on your code and submission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def independent_set(proposed_set: set[int], graph: dict[int, set[int]]) -> bool:
|
||||||
|
for vertex in proposed_set:
|
||||||
|
for adjecent in graph[vertex]:
|
||||||
|
if adjecent in proposed_set:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
# All modules for CS 412 must include a main method that allows it
|
||||||
|
# to imported and invoked from other python scripts
|
||||||
|
def main():
|
||||||
|
n = int(input())
|
||||||
|
|
||||||
|
graph: dict[int, set[int]] = {}
|
||||||
|
|
||||||
|
for _ in range(n):
|
||||||
|
vertecies = list(map(int, input().split()))
|
||||||
|
graph[vertecies[0]] = set(vertecies[1:])
|
||||||
|
|
||||||
|
proposed_set = set(map(int, input().split()))
|
||||||
|
|
||||||
|
print("TRUE" if independent_set(proposed_set, graph) else "FALSE")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
6
NP-Complete/input/sample1.txt
Normal file
6
NP-Complete/input/sample1.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
4
|
||||||
|
0 1
|
||||||
|
1 0 3
|
||||||
|
2
|
||||||
|
3 1
|
||||||
|
0 3 2
|
||||||
90
Railroad-Construction/README.md
Normal file
90
Railroad-Construction/README.md
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
# Lab 12: Railroad Construction
|
||||||
|
|
||||||
|
## Specification
|
||||||
|
|
||||||
|
There are _n_ cities that want to create a shared train network so that each
|
||||||
|
pair of cities is connected by rail to each of the other cities. The cost of
|
||||||
|
laying track is directly proportional to the distance between two cities. The
|
||||||
|
cost to lay one mile of railroad track is $1M. Your task is to determine the
|
||||||
|
lowest cost possible for laying the track so that all the cities are connected.
|
||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
A single line containing the number n of cities followed by n city coordinate
|
||||||
|
lines. Each of the coordinate lines is a pair of floating point numbers x y
|
||||||
|
giving the coordinates of the cities on a square grid (for this problem you may
|
||||||
|
assume the earth is flat and that the units of the grid structure are given in
|
||||||
|
miles).
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
The minimum amount of money (in millions) that must be spent to create the
|
||||||
|
railroad network. You can round this to a single decimal place.
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>Sample Input</td>
|
||||||
|
<td>Sample Output</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><pre>
|
||||||
|
3
|
||||||
|
0 1.5
|
||||||
|
1 0
|
||||||
|
0 0</pre></td>
|
||||||
|
<td><pre>$2.5M</pre></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><pre>
|
||||||
|
8
|
||||||
|
0 0
|
||||||
|
1 1
|
||||||
|
0 1
|
||||||
|
3 3
|
||||||
|
4 5
|
||||||
|
2 2
|
||||||
|
1 0
|
||||||
|
3 2</pre></td>
|
||||||
|
<td><pre>$8.7M</pre></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
## Hints
|
||||||
|
|
||||||
|
1. You may use our [connected_components.py](./connected_components.py) Download
|
||||||
|
connected_components.py in your code if you want., which will produce labels
|
||||||
|
for each of the vertices that correspond to their component. You will need to
|
||||||
|
use the adjacency list structure as suggested below if you wish to use this
|
||||||
|
code in its unmodified state.
|
||||||
|
2. You may have already envisioned a way to represent this problem as a graph.
|
||||||
|
Draw the graph in the small example above on paper. How many edges does it
|
||||||
|
have? If you are unsure of this, check with me before you start coding the
|
||||||
|
solution.
|
||||||
|
|
||||||
|
## Adjacency List
|
||||||
|
|
||||||
|
Augment your dictionary/set based adjacency structure to use a dictionary for
|
||||||
|
the edges (instead of a set as before). This will allow you to store the edge
|
||||||
|
weights as the values of this second dictionary.
|
||||||
|
|
||||||
|
## Method/Programming requirement
|
||||||
|
|
||||||
|
Your program must implement either Borůvka's algorithm (I suggest you use
|
||||||
|
Borůvka's) or Prims (not Kruskal). You must specify which algorithm you are
|
||||||
|
implementing in the comments. Any other method to compute the answer will result
|
||||||
|
in zero credit.
|
||||||
|
|
||||||
|
## Submission
|
||||||
|
|
||||||
|
Submit the code in a file named [cs412_railroad_a.py](./cs412_railroad_a.py) to
|
||||||
|
Gradescope. If you use the supplied copy of
|
||||||
|
[connected_components.py](./connected_components.py), you only need to import it
|
||||||
|
into your code (it will be available on Gradescope, so, no need to submit). If
|
||||||
|
you change connected_components.py, then please rename it and submit it as part
|
||||||
|
of your code (or you can copy/paste the code into your lab and just submit a
|
||||||
|
single file, it is up to you). You can import the code using the following
|
||||||
|
python:
|
||||||
|
|
||||||
|
```
|
||||||
|
from connected_components import count_and_label
|
||||||
|
```
|
||||||
71
Railroad-Construction/connected_components.py
Normal file
71
Railroad-Construction/connected_components.py
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
# Implementation of the count-and-label
|
||||||
|
# connected component counting algorithm.
|
||||||
|
#
|
||||||
|
# Author: John Bowers
|
||||||
|
# Version: Mar 17, 2021
|
||||||
|
|
||||||
|
# March 2022 -- molloykp
|
||||||
|
# Changed code to label components starting a 0 (instead of 1)
|
||||||
|
# October 2023 -- molloykp
|
||||||
|
# Change code to accept new adj list/hash map structure
|
||||||
|
|
||||||
|
# Version of the iterative dfs that takes as input
|
||||||
|
# a list of labels, one per vertex, and a starting
|
||||||
|
# vertex v and uses iterative depth-first-search
|
||||||
|
# to label each vertex with a given currentLabel
|
||||||
|
#
|
||||||
|
# Parameters:
|
||||||
|
# * graph is an adjaceny list where vertices name/keys are stored
|
||||||
|
# in a dictionary. Each vertex has its own dictionary
|
||||||
|
# where the key is the edge endpoint and the value is the
|
||||||
|
# weight of the edge.
|
||||||
|
# * v is the vertex to DFS from
|
||||||
|
# * labels is an array of length V which is -1 if the vertex is unvisited
|
||||||
|
# * currentLabel is the label to set on every visited vertex
|
||||||
|
#
|
||||||
|
# labels is an out-parameter and will be modified destructively during the
|
||||||
|
# run of this operation.
|
||||||
|
#
|
||||||
|
|
||||||
|
def dfs_label(graph, v, labels, currentLabel):
|
||||||
|
bag = [v]
|
||||||
|
while bag: # while bag is not empty
|
||||||
|
u = bag.pop()
|
||||||
|
if labels[u] == -1:
|
||||||
|
labels[u] = currentLabel
|
||||||
|
for w in graph[u]:
|
||||||
|
bag.append(w)
|
||||||
|
|
||||||
|
# Counts the number of connected components in the graph
|
||||||
|
# and labels each vertex with its connected component index
|
||||||
|
#
|
||||||
|
# Parameters:
|
||||||
|
# * graph given as an adjaceny list/set structure with vertices 0..(n-1)
|
||||||
|
#
|
||||||
|
# Returns:
|
||||||
|
# count, labels
|
||||||
|
# where count is the number of connected components in the graph
|
||||||
|
# and labels is the labeling of each vertex's connected component
|
||||||
|
# starting from index 0
|
||||||
|
def count_and_label(graph):
|
||||||
|
labels = [-1 for _ in range(len(graph))] # Initially all labels are -1
|
||||||
|
count = -1
|
||||||
|
for v in range(len(graph)): # for each vertex
|
||||||
|
if labels[v] == -1: # if v is not visited
|
||||||
|
count += 1
|
||||||
|
dfs_label(graph, v, labels, count)
|
||||||
|
return count+1, labels
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
graph = {
|
||||||
|
0: {1:2}, # 0's neighbors
|
||||||
|
1: {0:2, 2:4, 3:1}, # 1's neighbors
|
||||||
|
2: {1:4, 3:5}, # 2's neighbors
|
||||||
|
3: {1:1, 2:5}, # 3's neighbors
|
||||||
|
4: {5:8}, # 4's neighbors
|
||||||
|
5: {4:8} # 5's neighbors
|
||||||
|
}
|
||||||
|
|
||||||
|
count, labels = count_and_label(graph)
|
||||||
|
print(f"Number of connected components: {count}")
|
||||||
|
print(f"Vertex labels: {labels}")
|
||||||
113
Railroad-Construction/cs412_railroad_a.py
Normal file
113
Railroad-Construction/cs412_railroad_a.py
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
"""
|
||||||
|
name: Nicholas Tamassia
|
||||||
|
|
||||||
|
Honor Code and Acknowledgments:
|
||||||
|
|
||||||
|
This work complies with the JMU Honor Code.
|
||||||
|
|
||||||
|
Comments here on your code and submission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from collections import defaultdict
|
||||||
|
from math import sqrt
|
||||||
|
|
||||||
|
type Coordinate = tuple[float, float]
|
||||||
|
type CoordMap = dict[int, Coordinate]
|
||||||
|
type WeightedGraph = dict[int, dict[int, float]]
|
||||||
|
type Edge = tuple[int, int, float]
|
||||||
|
|
||||||
|
|
||||||
|
def distance(a: Coordinate, b: Coordinate) -> float:
|
||||||
|
x1, y1 = a
|
||||||
|
x2, y2 = b
|
||||||
|
return sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
|
||||||
|
|
||||||
|
|
||||||
|
def create_graph(coords: CoordMap) -> WeightedGraph:
|
||||||
|
graph: WeightedGraph = defaultdict(dict)
|
||||||
|
|
||||||
|
coord_items = coords.items()
|
||||||
|
|
||||||
|
for label1, coord1 in coord_items:
|
||||||
|
for label2, coord2 in coord_items:
|
||||||
|
if label1 == label2:
|
||||||
|
continue
|
||||||
|
|
||||||
|
weight = distance(coord1, coord2)
|
||||||
|
graph[label1][label2] = weight
|
||||||
|
graph[label2][label1] = weight
|
||||||
|
|
||||||
|
return graph
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_cost(graph: WeightedGraph) -> float:
|
||||||
|
parent: dict[int, int] = {v: v for v in graph}
|
||||||
|
rank: dict[int, int] = {v: 0 for v in graph}
|
||||||
|
|
||||||
|
def find(v: int) -> int:
|
||||||
|
if parent[v] != v:
|
||||||
|
parent[v] = find(parent[v])
|
||||||
|
return parent[v]
|
||||||
|
|
||||||
|
def union(u: int, v: int) -> None:
|
||||||
|
root_u, root_v = find(u), find(v)
|
||||||
|
if root_u == root_v:
|
||||||
|
return
|
||||||
|
if rank[root_u] < rank[root_v]:
|
||||||
|
parent[root_u] = root_v
|
||||||
|
elif rank[root_u] > rank[root_v]:
|
||||||
|
parent[root_v] = root_u
|
||||||
|
else:
|
||||||
|
parent[root_v] = root_u
|
||||||
|
rank[root_u] += 1
|
||||||
|
|
||||||
|
num_components = len(graph)
|
||||||
|
mst_edges: list[Edge] = []
|
||||||
|
|
||||||
|
while num_components > 1:
|
||||||
|
cheapest: dict[int, Edge] = {}
|
||||||
|
|
||||||
|
for u in graph:
|
||||||
|
for v, w in graph[u].items():
|
||||||
|
set_u = find(u)
|
||||||
|
set_v = find(v)
|
||||||
|
if set_u == set_v:
|
||||||
|
continue
|
||||||
|
if set_u not in cheapest or cheapest[set_u][2] > w:
|
||||||
|
cheapest[set_u] = (u, v, w)
|
||||||
|
if set_v not in cheapest or cheapest[set_v][2] > w:
|
||||||
|
cheapest[set_v] = (v, u, w)
|
||||||
|
|
||||||
|
for edge in cheapest.values():
|
||||||
|
u, v, w = edge
|
||||||
|
set_u = find(u)
|
||||||
|
set_v = find(v)
|
||||||
|
if set_u == set_v:
|
||||||
|
continue
|
||||||
|
mst_edges.append(edge)
|
||||||
|
union(set_u, set_v)
|
||||||
|
num_components -= 1
|
||||||
|
|
||||||
|
return sum(map(lambda x: x[2], mst_edges))
|
||||||
|
|
||||||
|
|
||||||
|
# All modules for CS 412 must include a main method that allows it
|
||||||
|
# to imported and invoked from other python scripts
|
||||||
|
def main():
|
||||||
|
n: int = int(input())
|
||||||
|
|
||||||
|
coords: CoordMap = {}
|
||||||
|
|
||||||
|
for i in range(0, n):
|
||||||
|
tokens = input().split()
|
||||||
|
coords[i] = (float(tokens[0]), float(tokens[1]))
|
||||||
|
|
||||||
|
weighted_graph = create_graph(coords)
|
||||||
|
|
||||||
|
cost = calculate_cost(weighted_graph)
|
||||||
|
|
||||||
|
print(f"${cost:.1f}M")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
4
Railroad-Construction/inputs/sample1.txt
Normal file
4
Railroad-Construction/inputs/sample1.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
3
|
||||||
|
0 1.5
|
||||||
|
1 0
|
||||||
|
0 0
|
||||||
9
Railroad-Construction/inputs/sample2.txt
Normal file
9
Railroad-Construction/inputs/sample2.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
8
|
||||||
|
0 0
|
||||||
|
1 1
|
||||||
|
0 1
|
||||||
|
3 3
|
||||||
|
4 5
|
||||||
|
2 2
|
||||||
|
1 0
|
||||||
|
3 2
|
||||||
@@ -8,6 +8,8 @@ Honor Code and Acknowledgments:
|
|||||||
Comments here on your code and submission.
|
Comments here on your code and submission.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import pprint
|
||||||
|
|
||||||
|
|
||||||
def valid_shuffle(a: str, b: str, c: str) -> bool:
|
def valid_shuffle(a: str, b: str, c: str) -> bool:
|
||||||
|
|
||||||
@@ -28,16 +30,22 @@ def valid_shuffle(a: str, b: str, c: str) -> bool:
|
|||||||
a_val: bool | None = memo[i + 1][j]
|
a_val: bool | None = memo[i + 1][j]
|
||||||
if a_val is None:
|
if a_val is None:
|
||||||
a_val = recurse(i + 1, j) if a[i] == c[k] else False
|
a_val = recurse(i + 1, j) if a[i] == c[k] else False
|
||||||
|
memo[i + 1][j] = a_val
|
||||||
|
|
||||||
b_val: bool | None = memo[i][j + 1]
|
b_val: bool | None = memo[i][j + 1]
|
||||||
if b_val is None:
|
if b_val is None:
|
||||||
b_val = recurse(i, j + 1) if b[j] == c[k] else False
|
b_val = recurse(i, j + 1) if b[j] == c[k] else False
|
||||||
|
memo[i][j + 1] = b_val
|
||||||
|
|
||||||
memo[i][j] = a_val or b_val
|
memo[i][j] = a_val or b_val
|
||||||
|
|
||||||
return a_val or b_val
|
return a_val or b_val
|
||||||
|
|
||||||
return recurse(0, 0)
|
val = recurse(0, 0)
|
||||||
|
|
||||||
|
pprint.pprint(memo)
|
||||||
|
|
||||||
|
return val
|
||||||
|
|
||||||
|
|
||||||
# All modules for CS 412 must include a main method that allows it
|
# All modules for CS 412 must include a main method that allows it
|
||||||
|
|||||||
16
devenv.lock
16
devenv.lock
@@ -3,10 +3,10 @@
|
|||||||
"devenv": {
|
"devenv": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"dir": "src/modules",
|
"dir": "src/modules",
|
||||||
"lastModified": 1757570236,
|
"lastModified": 1762789285,
|
||||||
"owner": "cachix",
|
"owner": "cachix",
|
||||||
"repo": "devenv",
|
"repo": "devenv",
|
||||||
"rev": "c57bded76fa6a885ab1dee2c75216cc23d58b311",
|
"rev": "379dd49a2ae3470e216cf07bfee4326e3c5a5baf",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -19,10 +19,10 @@
|
|||||||
"flake-compat": {
|
"flake-compat": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1747046372,
|
"lastModified": 1761588595,
|
||||||
"owner": "edolstra",
|
"owner": "edolstra",
|
||||||
"repo": "flake-compat",
|
"repo": "flake-compat",
|
||||||
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
|
"rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -40,10 +40,10 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1757588530,
|
"lastModified": 1762441963,
|
||||||
"owner": "cachix",
|
"owner": "cachix",
|
||||||
"repo": "git-hooks.nix",
|
"repo": "git-hooks.nix",
|
||||||
"rev": "b084b2c2b6bc23e83bbfe583b03664eb0b18c411",
|
"rev": "8e7576e79b88c16d7ee3bbd112c8d90070832885",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -74,10 +74,10 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1755783167,
|
"lastModified": 1761313199,
|
||||||
"owner": "cachix",
|
"owner": "cachix",
|
||||||
"repo": "devenv-nixpkgs",
|
"repo": "devenv-nixpkgs",
|
||||||
"rev": "4a880fb247d24fbca57269af672e8f78935b0328",
|
"rev": "d1c30452ebecfc55185ae6d1c983c09da0c274ff",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
Reference in New Issue
Block a user