Spaces:
Sleeping
Sleeping
| """ | |
| USSU Algorithm Analyzer v4.0 - Greedy Algorithms Suite | |
| Activity Selection, Huffman, Fractional Knapsack, and more. | |
| """ | |
| import heapq | |
| from typing import List, Dict, Tuple, Any | |
| from utils.core import profile_algorithm, OperationCounter | |
| class GreedyAlgorithms(OperationCounter): | |
| """Greedy algorithm collection for ADA""" | |
| def __init__(self): | |
| super().__init__() | |
| def reset(self): | |
| self.reset_counters() | |
| # ==================== ACTIVITY SELECTION ==================== | |
| def activity_selection(self, activities: List[Tuple[int, int, str]]) -> Dict: | |
| """ | |
| activities: list of (start, finish, name) | |
| Returns maximum set of non-conflicting activities. | |
| """ | |
| self.reset() | |
| # Sort by finish time | |
| sorted_acts = sorted(activities, key=lambda x: x[1]) | |
| selected = [sorted_acts[0]] | |
| last_finish = sorted_acts[0][1] | |
| for i in range(1, len(sorted_acts)): | |
| self.iterations += 1 | |
| self.comparisons += 1 | |
| if sorted_acts[i][0] >= last_finish: | |
| selected.append(sorted_acts[i]) | |
| last_finish = sorted_acts[i][1] | |
| return { | |
| 'algorithm': 'Activity Selection (Greedy)', | |
| 'selected': selected, | |
| 'count': len(selected), | |
| 'time_complexity': 'O(n log n)', | |
| 'space_complexity': 'O(n)', | |
| 'iterations': self.iterations, | |
| 'comparisons': self.comparisons, | |
| } | |
| # ==================== FRACTIONAL KNAPSACK ==================== | |
| def fractional_knapsack(self, weights: List[int], values: List[int], capacity: int) -> Dict: | |
| self.reset() | |
| n = len(weights) | |
| items = [(values[i] / weights[i], weights[i], values[i], i) for i in range(n)] | |
| items.sort(reverse=True) # Sort by value/weight ratio descending | |
| total_value = 0.0 | |
| selected = [] | |
| remaining = capacity | |
| for ratio, w, v, idx in items: | |
| self.iterations += 1 | |
| self.comparisons += 1 | |
| if remaining >= w: | |
| selected.append((idx, 1.0, v)) | |
| total_value += v | |
| remaining -= w | |
| else: | |
| fraction = remaining / w | |
| selected.append((idx, fraction, v * fraction)) | |
| total_value += v * fraction | |
| remaining = 0 | |
| break | |
| return { | |
| 'algorithm': 'Fractional Knapsack (Greedy)', | |
| 'max_value': total_value, | |
| 'selected_items': selected, | |
| 'time_complexity': 'O(n log n)', | |
| 'space_complexity': 'O(n)', | |
| 'iterations': self.iterations, | |
| 'comparisons': self.comparisons, | |
| } | |
| # ==================== HUFFMAN CODING ==================== | |
| def huffman_coding(self, frequencies: Dict[str, int]) -> Dict: | |
| self.reset() | |
| if len(frequencies) == 0: | |
| return {'algorithm': 'Huffman Coding', 'codes': {}, 'time_complexity': 'O(n log n)', 'space_complexity': 'O(n)'} | |
| heap = [[weight, [symbol, ""]] for symbol, weight in frequencies.items()] | |
| heapq.heapify(heap) | |
| while len(heap) > 1: | |
| self.iterations += 1 | |
| lo = heapq.heappop(heap) | |
| hi = heapq.heappop(heap) | |
| for pair in lo[1:]: | |
| pair[1] = '0' + pair[1] | |
| for pair in hi[1:]: | |
| pair[1] = '1' + pair[1] | |
| heapq.heappush(heap, [lo[0] + hi[0]] + lo[1:] + hi[1:]) | |
| result = sorted(heapq.heappop(heap)[1:], key=lambda p: (len(p[-1]), p)) | |
| codes = {symbol: code for symbol, code in result} | |
| # Calculate total bits | |
| total_bits = sum(frequencies[s] * len(codes[s]) for s in frequencies) | |
| return { | |
| 'algorithm': 'Huffman Coding', | |
| 'codes': codes, | |
| 'total_bits': total_bits, | |
| 'average_bits': total_bits / sum(frequencies.values()), | |
| 'time_complexity': 'O(n log n)', | |
| 'space_complexity': 'O(n)', | |
| 'iterations': self.iterations, | |
| } | |
| # ==================== JOB SEQUENCING WITH DEADLINES ==================== | |
| def job_sequencing(self, jobs: List[Tuple[str, int, int]]) -> Dict: | |
| """ | |
| jobs: list of (job_id, deadline, profit) | |
| """ | |
| self.reset() | |
| n = len(jobs) | |
| # Sort by profit descending | |
| jobs_sorted = sorted(jobs, key=lambda x: x[2], reverse=True) | |
| max_deadline = max(j[1] for j in jobs) | |
| slot = [-1] * (max_deadline + 1) | |
| scheduled = [] | |
| total_profit = 0 | |
| for job_id, deadline, profit in jobs_sorted: | |
| self.iterations += 1 | |
| # Find latest available slot before deadline | |
| for t in range(min(deadline, max_deadline), 0, -1): | |
| self.comparisons += 1 | |
| if slot[t] == -1: | |
| slot[t] = job_id | |
| scheduled.append((job_id, t)) | |
| total_profit += profit | |
| break | |
| return { | |
| 'algorithm': 'Job Sequencing with Deadlines', | |
| 'scheduled_jobs': scheduled, | |
| 'total_profit': total_profit, | |
| 'time_complexity': 'O(n²)', | |
| 'space_complexity': 'O(n)', | |
| 'iterations': self.iterations, | |
| 'comparisons': self.comparisons, | |
| } | |
| # ==================== MINIMUM COINS (GREEDY) ==================== | |
| def minimum_coins_greedy(self, coins: List[int], amount: int) -> Dict: | |
| """Greedy coin change - works for canonical systems like US coins""" | |
| self.reset() | |
| coins_sorted = sorted(coins, reverse=True) | |
| count = 0 | |
| used = [] | |
| remaining = amount | |
| for coin in coins_sorted: | |
| self.iterations += 1 | |
| if remaining >= coin: | |
| num = remaining // coin | |
| count += num | |
| used.extend([coin] * num) | |
| remaining -= num * coin | |
| optimal = remaining == 0 | |
| return { | |
| 'algorithm': 'Minimum Coins (Greedy)', | |
| 'min_coins': count if optimal else -1, | |
| 'coins_used': used if optimal else [], | |
| 'optimal': optimal, | |
| 'warning': None if optimal else 'Greedy may not be optimal for this coin system!', | |
| 'time_complexity': 'O(|coins|)', | |
| 'space_complexity': 'O(1)', | |
| 'iterations': self.iterations, | |
| } | |