Skip to content

Commit 94a29ce

Browse files
Merge pull request #108 from indrasuthar07/greedy
feat: greedy algo
2 parents 523716b + 3b767d9 commit 94a29ce

File tree

6 files changed

+562
-0
lines changed

6 files changed

+562
-0
lines changed

src/App.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Searchingpage from "./pages/searching/searchingPage";
1010
import RecursionPage from "./pages/Recursion/RecursionPage";
1111
import Treepage from "./pages/Tree/Treepage";
1212
import SlidingWindowPage from "./pages/sliding-window/SlidingWindowPage";
13+
import GreedyPage from "./pages/greedy/GreedyPage";
1314
function App() {
1415
return (
1516
<Router>
@@ -24,6 +25,7 @@ function App() {
2425
<Route path="/recursion" element={<RecursionPage/>}/>
2526
<Route path="/tree" element={<Treepage />} />
2627
<Route path="/sliding-window" element={<SlidingWindowPage/>}/>
28+
<Route path="/greedy" element={<GreedyPage />} />
2729
</Routes>
2830
</Router>
2931
);
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
export function* fractionalKnapsack(weights, values, capacity) {
2+
const n = weights.length;
3+
const items = [];
4+
for (let i = 0; i < n; i++) {
5+
items.push({index: i, weight: weights[i], value: values[i], ratio: values[i] / weights[i]});
6+
}
7+
8+
yield {
9+
type: "calculate_ratios",
10+
message: "Calculating value-to-weight ratio for each item",
11+
items: items.map(item => ({ ...item })),
12+
capacity,
13+
selectedItems: [],
14+
totalValue: 0,
15+
remainingCapacity: capacity
16+
};
17+
18+
items.sort((a, b) => b.ratio - a.ratio);
19+
20+
yield {
21+
type: "sort_items",
22+
message: "Sorting items by value-to-weight ratio (descending) - Greedy approach",
23+
items: items.map(item => ({ ...item })), capacity, selectedItems: [], totalValue: 0, remainingCapacity: capacity
24+
};
25+
26+
const selectedItems = [];
27+
let totalValue = 0;
28+
let remainingCapacity = capacity;
29+
30+
for (let i = 0; i < items.length; i++) {
31+
const item = items[i];
32+
33+
yield {
34+
type: "consider_item",
35+
message: `Considering item ${item.index + 1}: weight=${item.weight}, value=${item.value}, ratio=${item.ratio.toFixed(2)}`,
36+
items: items.map(item => ({ ...item })),
37+
currentItem: { ...item }, capacity, selectedItems: selectedItems.map(si => ({ ...si })), totalValue, remainingCapacity
38+
};
39+
40+
if (remainingCapacity <= 0) {
41+
yield {
42+
type: "skip_item",
43+
message: `Skipping item ${item.index + 1}: No remaining capacity`,
44+
items: items.map(item => ({ ...item })),
45+
currentItem: { ...item },capacity, selectedItems: selectedItems.map(si => ({ ...si })), totalValue, remainingCapacity
46+
};
47+
break;
48+
}
49+
50+
if (item.weight <= remainingCapacity) {
51+
const fraction = 1.0;
52+
const itemValue = item.value;
53+
const itemWeight = item.weight;
54+
55+
selectedItems.push({index: item.index, weight: itemWeight, value: itemValue, ratio: item.ratio, fraction: fraction, actualWeight: itemWeight, actualValue: itemValue});
56+
57+
totalValue += itemValue;
58+
remainingCapacity -= itemWeight;
59+
60+
yield {
61+
type: "take_full",
62+
message: `Taking full item ${item.index + 1}: ${itemWeight}kg (value: ${itemValue})`,
63+
items: items.map(item => ({ ...item })),
64+
currentItem: { ...item },
65+
capacity,
66+
selectedItems: selectedItems.map(si => ({ ...si })),
67+
totalValue,
68+
remainingCapacity
69+
};
70+
} else {
71+
const fraction = remainingCapacity / item.weight;
72+
const actualWeight = remainingCapacity;
73+
const actualValue = item.value * fraction;
74+
75+
selectedItems.push({index: item.index, weight: item.weight, value: item.value, ratio: item.ratio, fraction: fraction, actualWeight: actualWeight, actualValue: actualValue});
76+
77+
totalValue += actualValue;
78+
remainingCapacity = 0;
79+
80+
yield {
81+
type: "take_fraction",
82+
message: `Taking ${(fraction * 100).toFixed(1)}% of item ${item.index + 1}: ${actualWeight.toFixed(2)}kg (value: ${actualValue.toFixed(2)})`,
83+
items: items.map(item => ({ ...item })), currentItem: { ...item }, capacity, selectedItems: selectedItems.map(si => ({ ...si })), totalValue, remainingCapacity, fraction
84+
};
85+
break;
86+
}
87+
}
88+
89+
yield {type: "complete", message: `Knapsack filled! Total value: ${totalValue.toFixed(2)}`, items: items.map(item => ({ ...item })), capacity, selectedItems: selectedItems.map(si => ({ ...si })), totalValue, remainingCapacity};
90+
return { selectedItems, totalValue, remainingCapacity};
91+
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import React from "react";
2+
3+
export default function FractionalKnapsackVisualizer({items = [], currentStep = null, capacity = 0}) {
4+
if (!currentStep) {
5+
return (
6+
<div className="flex items-center justify-center h-64 bg-gray-800 rounded-lg border border-gray-700">
7+
<div className="text-center">
8+
<div className="text-gray-400">No data to visualize</div>
9+
</div>
10+
</div>
11+
);
12+
}
13+
const step = currentStep;
14+
const selectedItems = step.selectedItems || [];
15+
const totalValue = step.totalValue || 0;
16+
const remainingCapacity = step.remainingCapacity !== undefined ? step.remainingCapacity : capacity;
17+
const usedCapacity = capacity - remainingCapacity;
18+
19+
const getItemStatus = (item) => {
20+
const selected = selectedItems.find(si => si.index === item.index);
21+
22+
if (selected) {
23+
return selected.fraction === 1.0 ? "full" : "partial";
24+
}
25+
26+
if (step.currentItem && step.currentItem.index === item.index) {
27+
if (step.type === "consider_item") {
28+
return "considering";
29+
} else if (step.type === "skip_item") {
30+
return "skipped";
31+
}
32+
}
33+
34+
return "not_selected";
35+
};
36+
37+
const getItemClass = (status) => {
38+
switch (status) {
39+
case "full":
40+
return "bg-green-600 border-green-500";
41+
case "partial":
42+
return "bg-yellow-600 border-yellow-500";
43+
case "considering":
44+
return "bg-blue-600 border-blue-500";
45+
case "skipped":
46+
return "bg-gray-600 border-gray-500 opacity-50";
47+
default:
48+
return "bg-gray-700 border-gray-600";
49+
}
50+
};
51+
return (
52+
<div className="w-3/4 h-full mx-auto space-y-4">
53+
<div className="bg-gray-800 rounded-lg p-4 border border-gray-700">
54+
<h3 className="text-sm font-bold mb-3 text-white">Items (Sorted by Value/Weight Ratio)</h3>
55+
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-2">
56+
{step.items?.map((item, idx) => {
57+
const status = getItemStatus(item);
58+
const selected = selectedItems.find(si => si.index === item.index);
59+
return (
60+
<div
61+
key={item.index}
62+
className={`border rounded p-2 transition-colors duration-200 ${getItemClass(status)}`}
63+
>
64+
<div className="flex justify-between items-center mb-1">
65+
<div className="font-bold text-white text-xs">Item {item.index + 1}</div>
66+
<div className="text-xs bg-white/20 px-1 py-0.5 rounded text-white">
67+
{item.ratio.toFixed(2)}
68+
</div>
69+
</div>
70+
<div className="space-y-0.5 text-xs text-white">
71+
<div className="flex justify-between">
72+
<span>W:</span>
73+
<span className="font-semibold">{item.weight}</span>
74+
</div>
75+
<div className="flex justify-between">
76+
<span>V:</span>
77+
<span className="font-semibold">{item.value}</span>
78+
</div>
79+
{selected && (
80+
<div className="border-t border-white/20 pt-1 mt-1">
81+
<div className="text-xs font-bold">
82+
{selected.fraction === 1.0
83+
? "100%"
84+
: `${(selected.fraction * 100).toFixed(0)}%`}
85+
</div>
86+
<div className="text-xs">
87+
{selected.actualWeight.toFixed(1)}kg
88+
</div>
89+
</div>
90+
)}
91+
</div>
92+
</div>
93+
);
94+
})}
95+
</div>
96+
</div>
97+
<div className="bg-gray-800 rounded-lg p-4 border border-gray-700">
98+
<h3 className="text-sm font-bold mb-3 text-white">Knapsack</h3>
99+
<div className="space-y-3">
100+
<div>
101+
<div className="flex justify-between text-xs mb-1 text-gray-300">
102+
<span>Capacity</span>
103+
<span className="font-semibold text-white">
104+
{usedCapacity.toFixed(1)} / {capacity} kg
105+
</span>
106+
</div>
107+
<div className="w-full bg-gray-700 rounded-full h-8 overflow-hidden border border-gray-600">
108+
<div
109+
className="h-full bg-green-600 flex items-center justify-center text-white font-bold text-xs transition-all duration-300"
110+
style={{ width: `${Math.min((usedCapacity / capacity) * 100, 100)}%` }}>
111+
{capacity > 0 ? ((usedCapacity / capacity) * 100).toFixed(0) : 0}%
112+
</div>
113+
</div>
114+
</div>
115+
{selectedItems.length > 0 && (
116+
<div className="mt-2">
117+
<h4 className="text-xs font-semibold text-gray-300 mb-2">Selected Items:</h4>
118+
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-2">
119+
{selectedItems.map((item, idx) => (
120+
<div
121+
key={idx}
122+
className={`p-2 rounded border text-xs ${
123+
item.fraction === 1.0
124+
? "bg-green-600/30 border-green-500"
125+
: "bg-yellow-600/30 border-yellow-500"
126+
}`}
127+
>
128+
<div className="text-white">
129+
<div className="font-semibold">Item {item.index + 1}</div>
130+
<div className="text-gray-300 text-xs">
131+
{item.fraction === 1.0 ? "Full" : `${(item.fraction * 100).toFixed(0)}%`}
132+
</div>
133+
<div className="text-xs mt-1">
134+
{item.actualWeight.toFixed(1)}kg
135+
</div>
136+
<div className="text-xs text-gray-300">
137+
V: {item.actualValue.toFixed(1)}
138+
</div>
139+
</div>
140+
</div>
141+
))}
142+
</div>
143+
</div>
144+
)}
145+
<div className="mt-3 p-3 rounded borde">
146+
<div className="flex gap-4 items-center">
147+
<span className="text-sm font-semibold text-white">Total Value:</span>
148+
<span className="text-xl font-bold text-white">{totalValue.toFixed(2)}</span>
149+
</div>
150+
{remainingCapacity > 0 && step.type === "complete" && (
151+
<div className="text-xs text-gray-300 mt-1">
152+
Remaining: {remainingCapacity.toFixed(1)} kg
153+
</div>
154+
)}
155+
</div>
156+
</div>
157+
</div>
158+
</div>
159+
);
160+
}
161+

src/pages/Homepage.jsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,15 @@ const sections = [
8989
link: "/tree",
9090
flag: false,
9191
},
92+
{
93+
title: "Greedy Algorithms",
94+
description:
95+
"Watch how greedy choices lead to optimal solutions in problems like Fractional Knapsack.",
96+
phase: "Phase 2",
97+
img: "",
98+
link: "/greedy",
99+
flag: false,
100+
},
92101
];
93102

94103
const Homepage = () => {

0 commit comments

Comments
 (0)