pushing read me
This commit is contained in:
parent
df2141c62d
commit
35199019fe
166
README.md
Normal file
166
README.md
Normal file
@ -0,0 +1,166 @@
|
||||
# Cut Rod Problem — Dynamic Programming
|
||||
|
||||
A complete implementation of the classic **Rod Cutting Problem** from *Introduction to Algorithms* (CLRS), with three algorithmic approaches and an interactive browser-based visualizer.
|
||||
|
||||
---
|
||||
|
||||
## The Problem
|
||||
|
||||
You have a rod of length **n** inches and a price table that tells you how much each cut length sells for. You want to cut the rod into pieces (or keep it whole) to **maximize total revenue**.
|
||||
|
||||
```
|
||||
Length: 1 2 3 4 5 6 7 8 9 10
|
||||
Price: 1 5 8 9 10 17 17 20 24 30
|
||||
```
|
||||
|
||||
For a rod of length 4, the best strategy is two pieces of length 2 (5 + 5 = **$10**), not selling it whole for $9.
|
||||
|
||||
This is a classic **optimal substructure** problem: the best way to cut a rod of length n depends on the best ways to cut shorter rods — making it a perfect fit for dynamic programming.
|
||||
|
||||
---
|
||||
|
||||
## Algorithms
|
||||
|
||||
### 1. Naive Recursion — `simple_cut_rod(p, n)`
|
||||
|
||||
Tries every possible first cut at position i and recurses on the remainder.
|
||||
|
||||
```python
|
||||
def simple_cut_rod(p, n):
|
||||
if n == 0:
|
||||
return 0
|
||||
q = float('-inf')
|
||||
for i in range(1, n + 1):
|
||||
q = max(q, p[i] + simple_cut_rod(p, n - i))
|
||||
return q
|
||||
```
|
||||
|
||||
**Time complexity:** O(2ⁿ) — exponential. Each subproblem is recomputed from scratch.
|
||||
|
||||
---
|
||||
|
||||
### 2. Top-Down DP with Memoization — `memoized_cut_rod(p, n)`
|
||||
|
||||
Same recursion as above, but caches results in an array `r`. If `r[n]` has already been computed, return it immediately.
|
||||
|
||||
```python
|
||||
def memoized_cut_rod(p, n):
|
||||
r = [float('-inf')] * (n + 1)
|
||||
return _memoized_cut_rod_aux(p, n, r)
|
||||
```
|
||||
|
||||
**Time complexity:** O(n²) — each of the n subproblems is solved exactly once.
|
||||
|
||||
---
|
||||
|
||||
### 3. Bottom-Up DP — `bottom_up_cut_rod(p, n)`
|
||||
|
||||
Fills a table `r[0..n]` iteratively from the smallest subproblem up. For each rod length j, tries every first cut i from 1 to j and stores the best result.
|
||||
|
||||
```python
|
||||
def bottom_up_cut_rod(p, n):
|
||||
r = [0] * (n + 1)
|
||||
for j in range(1, n + 1):
|
||||
q = float('-inf')
|
||||
for i in range(1, j + 1):
|
||||
q = max(q, p[i] + r[j - i])
|
||||
r[j] = q
|
||||
return r[n]
|
||||
```
|
||||
|
||||
**Time complexity:** O(n²) | **Space complexity:** O(n)
|
||||
|
||||
This is the approach animated in the visualizer.
|
||||
|
||||
---
|
||||
|
||||
## Complexity Comparison
|
||||
|
||||
| Approach | Time | Space | Notes |
|
||||
|---|---|---|---|
|
||||
| Naive recursion | O(2ⁿ) | O(n) call stack | Impractical for n > 30 |
|
||||
| Top-down (memoized) | O(n²) | O(n) | Natural recursive structure |
|
||||
| Bottom-up | O(n²) | O(n) | No recursion overhead, cache-friendly |
|
||||
|
||||
---
|
||||
|
||||
## Project Files
|
||||
|
||||
```
|
||||
.
|
||||
├── cut_rod.py # Python implementation (all 3 algorithms)
|
||||
├── visualization.html # Interactive browser visualizer
|
||||
└── Cut Rod Problem/
|
||||
└── Cut Rod Problem/
|
||||
├── Program.cs # Original C# implementation
|
||||
└── Data.txt # Price table (33 prices, space-separated)
|
||||
```
|
||||
|
||||
### `Data.txt` — Price Table
|
||||
|
||||
```
|
||||
1 5 8 9 10 17 17 20 24 30 33 31 31 31 40 39 20 45 42 46 70 76 77 80 85 90 95 100 110 120 111 200 678
|
||||
```
|
||||
|
||||
Prices for lengths 1 through 33 inches.
|
||||
|
||||
---
|
||||
|
||||
## Running the Python Version
|
||||
|
||||
```bash
|
||||
python3 cut_rod.py
|
||||
```
|
||||
|
||||
You will be prompted for a rod length. Switch between algorithms by uncommenting the desired line in `main()`:
|
||||
|
||||
```python
|
||||
best_price = memoized_cut_rod(prices, n) # default
|
||||
# best_price = bottom_up_cut_rod(prices, n)
|
||||
# best_price = simple_cut_rod(prices, n) # slow for n > 25
|
||||
```
|
||||
|
||||
**Example output for n = 10:**
|
||||
```
|
||||
Enter number of Inches: 10
|
||||
Best Revenue is upto : 30
|
||||
Time Elapsed : 0.000021875s
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Running the Visualizer
|
||||
|
||||
Open `visualization.html` directly in any modern browser — no server or dependencies needed.
|
||||
|
||||
```bash
|
||||
open visualization.html # macOS
|
||||
start visualization.html # Windows
|
||||
xdg-open visualization.html # Linux
|
||||
```
|
||||
|
||||
### Controls
|
||||
|
||||
| Control | Action |
|
||||
|---|---|
|
||||
| Rod Length | Set the rod length (1–25). Resets the animation. |
|
||||
| Speed | Adjust playback speed (1× slow → 10× fast). |
|
||||
| ▶ Play | Run the animation automatically. |
|
||||
| ⏸ Pause | Pause at the current step. |
|
||||
| ⏭ Step | Advance one step forward. |
|
||||
| ⏮ Back | Go one step backward. |
|
||||
| ↺ Reset | Restart from the beginning. |
|
||||
|
||||
---
|
||||
|
||||
## Example: Rod of Length 10
|
||||
|
||||
The algorithm finds that the maximum revenue is **$30**, achieved by keeping the rod uncut (selling the full 10-inch piece at $30).
|
||||
|
||||
For a rod of length 7, the optimal is **3 + 4 = $17** (8 + 9 = $17, compared to selling whole for $17 — same either way, but the s-table reveals the first cut chosen).
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- Cormen, T. H., Leiserson, C. E., Rivest, R. L., & Stein, C. (2009). *Introduction to Algorithms* (3rd ed.), Section 15.1 — Rod cutting.
|
||||
@ -314,6 +314,81 @@ input[type=range] { width: 110px; accent-color: var(--purple); }
|
||||
.r { color: var(--red); }
|
||||
.p { color: var(--purple); }
|
||||
.o { color: var(--orange); }
|
||||
|
||||
/* ── LEGEND ──────────────────────────────────── */
|
||||
.legend {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px 20px;
|
||||
justify-content: center;
|
||||
max-width: 1120px;
|
||||
margin: 0 auto 20px;
|
||||
padding: 12px 20px;
|
||||
background: var(--surf);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
font-size: .78rem;
|
||||
}
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
color: var(--dim);
|
||||
}
|
||||
.swatch {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 3px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.swatch-outline {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 3px;
|
||||
flex-shrink: 0;
|
||||
border: 2px solid;
|
||||
}
|
||||
|
||||
/* ── EXPLAINER ───────────────────────────────── */
|
||||
.explainer {
|
||||
max-width: 1120px;
|
||||
margin: 20px auto 0;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 14px;
|
||||
}
|
||||
@media (max-width: 800px) {
|
||||
.explainer { grid-template-columns: 1fr; }
|
||||
}
|
||||
.exp-card {
|
||||
background: var(--surf);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
padding: 18px 20px;
|
||||
}
|
||||
.exp-card h3 {
|
||||
font-size: .8rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .08em;
|
||||
color: var(--dim);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.exp-card p, .exp-card li {
|
||||
font-size: .83rem;
|
||||
line-height: 1.65;
|
||||
color: #a0aab4;
|
||||
}
|
||||
.exp-card ul { padding-left: 16px; }
|
||||
.exp-card li { margin-bottom: 5px; }
|
||||
.exp-card code {
|
||||
font-family: 'SFMono-Regular', 'Consolas', monospace;
|
||||
font-size: .8rem;
|
||||
background: var(--bg);
|
||||
padding: 1px 5px;
|
||||
border-radius: 4px;
|
||||
color: var(--orange);
|
||||
}
|
||||
.exp-card .accent { color: var(--text); font-weight: 600; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@ -339,6 +414,34 @@ input[type=range] { width: 110px; accent-color: var(--purple); }
|
||||
<button class="btn btn-secondary" id="btn-reset">↺ Reset</button>
|
||||
</div>
|
||||
|
||||
<!-- LEGEND -->
|
||||
<div class="legend">
|
||||
<div class="legend-item">
|
||||
<div class="swatch" style="background:var(--red)"></div>
|
||||
<span>Cut piece — sells for <strong style="color:var(--text)">p[i]</strong></span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="swatch" style="background:var(--blue)"></div>
|
||||
<span>Remainder — best revenue already known as <strong style="color:var(--text)">r[j−i]</strong></span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="swatch-outline" style="border-color:var(--yellow);background:#2b2400"></div>
|
||||
<span><strong style="color:var(--yellow)">Yellow cell</strong> — currently being computed</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="swatch" style="background:#122620"></div>
|
||||
<span><strong style="color:var(--green)">Green cell</strong> — finalized value</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="swatch" style="background:#0d1f36"></div>
|
||||
<span><strong style="color:var(--blue)">Blue cell</strong> — value being read (r[j−i])</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="swatch" style="background:#1a1030"></div>
|
||||
<span><strong style="color:var(--purple)">Purple cell</strong> — optimal first cut stored in s[j]</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layout">
|
||||
|
||||
<!-- LEFT COLUMN -->
|
||||
@ -395,6 +498,47 @@ input[type=range] { width: 110px; accent-color: var(--purple); }
|
||||
|
||||
</div>
|
||||
|
||||
<!-- EXPLAINER -->
|
||||
<div class="explainer">
|
||||
|
||||
<div class="exp-card">
|
||||
<h3>The Problem</h3>
|
||||
<p>
|
||||
You have a rod of length <span class="accent">n</span> inches and a price table
|
||||
<code>p[1..n]</code> where <code>p[i]</code> is what a piece of length <code>i</code> sells for.
|
||||
You can cut the rod into any combination of integer lengths. The goal is to
|
||||
<span class="accent">maximize total revenue</span>.
|
||||
</p>
|
||||
<br>
|
||||
<p>
|
||||
A rod of length 4 sold whole earns $9, but two pieces of length 2 earn $5 + $5 = <span class="accent">$10</span>.
|
||||
Finding the best combination by brute force takes O(2ⁿ) time — dynamic programming reduces this to <span class="accent">O(n²)</span>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="exp-card">
|
||||
<h3>How the Algorithm Works</h3>
|
||||
<ul>
|
||||
<li><span class="accent">Build up from small rods.</span> Compute the best revenue for length 1, then 2, then 3 … up to n. Each answer reuses earlier answers.</li>
|
||||
<li><span class="accent">For each length j</span>, try every possible first cut at position <code>i = 1 … j</code>. The candidate revenue is <code>p[i] + r[j−i]</code>: sell the first piece and optimally cut the rest.</li>
|
||||
<li><span class="accent">Store the best.</span> <code>r[j]</code> holds the maximum over all cuts. <code>s[j]</code> records which cut produced that maximum — used later to reconstruct the actual pieces.</li>
|
||||
<li><span class="accent">Reconstruct.</span> Follow <code>s[n] → s[n−s[n]] → …</code> to read off the optimal cut sequence.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="exp-card">
|
||||
<h3>Reading the Visualization</h3>
|
||||
<ul>
|
||||
<li><span class="accent">Rod bar:</span> the red segment is the piece being sold now (length <code>i</code>); the blue segment is the remainder whose best revenue is already in the table.</li>
|
||||
<li><span class="accent">DP table row r[j]:</span> fills left-to-right. The yellow cell is being computed right now; blue cells are the ones being looked up.</li>
|
||||
<li><span class="accent">DP table row s[j]:</span> once a cell is finalized (purple), it tells you the optimal first cut for that rod length.</li>
|
||||
<li><span class="accent">Pseudocode:</span> the highlighted line shows exactly which line of the algorithm the current step corresponds to.</li>
|
||||
<li><span class="accent">Optimal Solution</span> (shown at the end): the colored bar divides the rod into its best pieces, each labeled with its length and sale price.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// ── DATA ────────────────────────────────────────
|
||||
const PRICE_DATA = [0,1,5,8,9,10,17,17,20,24,30,33,31,31,31,40,39,20,45,42,46,70,76,77,80,85,90,95,100,110,120,111,200,678];
|
||||
|
||||
Loading…
Reference in New Issue
Block a user