public static int MinimumNumberOfBoats_UdemySolution(int[] weights, int maxWeight, int weightDiff)
        {
            // * the solution provided by the instructor doesn't take edge cases into account. Had to add them by had.
            // * algo on the last if, i had to add a comparison, since the top.key && i might be the same, and if !isTaken[i]
            // * that value is never popped
            // * this solution seems overly complicated, since every solution works for every other lower solution
            int n = weights.Length;

            if (n == 0)
            {
                return(0);
            }
            if (n == 1)
            {
                if (weights[0] <= weightDiff)
                {
                    return(1);
                }
                return(0);
            }
            Array.Sort(weights);
            int               ans     = 0;
            int               p       = 0;
            List <bool>       isTaken = new List <bool>(new bool[n]);
            MaxHeap <BoatKey> pq      = new MaxHeap <BoatKey>();

            for (int i = n - 1; i >= 0; i--)
            {
                while (p < i && weights[p] + weights[i] <= maxWeight)
                {
                    pq.Insert(new BoatKey(p, weights[p]));
                    p++;
                }
                if (isTaken[i])
                {
                    continue;
                }

                while (!pq.IsEmpty() && weights[i] - pq.Top().Weight <= weightDiff)
                {
                    if (isTaken[pq.Top().Key] || i == pq.Top().Key)
                    {
                        pq.RemoveTop();
                        continue;
                    }
                    isTaken[i] = isTaken[pq.Top().Key] = true;
                    pq.RemoveTop();
                    break;
                }
                ans++;
            }
            return(ans);
        }
        public static int MonsterKiller(int[] dmg, int hp, int potions)
        {
            if (dmg.Length == 0)
            {
                return(0);
            }
            MaxHeap <int> kills = new MaxHeap <int>();
            int           i     = 0;
            int           l     = dmg.Length;

            while (hp > 0 && i < l)
            {
                if (dmg[i] > hp)
                {
                    if (potions == 0)
                    {
                        return(i);
                    }
                    else
                    {
                        potions--;
                        if (!kills.IsEmpty())
                        {
                            if (dmg[i] <= kills.Top())
                            {
                                hp += kills.RemoveTop();
                                kills.Insert(dmg[i]);
                            }
                        }
                    }
                }
                else
                {
                    hp -= dmg[i];
                    if (dmg[i] > 0)
                    {
                        kills.Insert(dmg[i]);
                    }
                }
                i++;
            }
            return(i);
        }
        /*
         *  Given arrivals & departures from several trains, find the min number of platforms needed to avoid waiting trains.
         */
        public static int MinimumNumberOfPlatforms(List <ScheduleActivity> schedule)
        {
            if (schedule.Count < 2)
            {
                return(schedule.Count);
            }
            // * Using a MinHeap, I can always get the minimun time value (prioritizing departures over arrivals at the same time)
            // * alongside it's operation (Arrival or Departure)
            var realSchedule = new MaxHeap <ScheduleNode>();

            foreach (var t in schedule)
            {
                realSchedule.Insert(new ScheduleNode(t.Start * -1, true));
                realSchedule.Insert(new ScheduleNode(t.End * -1, false));
            }
            int ret = 0;
            int remainingPlatforms = 0;

            // * Whenever a train arrives, if there're remaining platforms, use them
            // * Otherwise, you need a new platform.
            // * When a train departs, the you've got a new remaining platform to use.
            while (!realSchedule.IsEmpty())
            {
                var s = realSchedule.RemoveTop();
                if (s.Arriving)
                {
                    if (remainingPlatforms > 0)
                    {
                        remainingPlatforms--;
                    }
                    else
                    {
                        ret++;
                    }
                }
                else
                {
                    remainingPlatforms++;
                }
            }
            return(ret);
        }
        public static int ConnectRopes(int[] ropes)
        {
            MaxHeap <int> minHeap = new MaxHeap <int>();

            for (int i = 0; i < ropes.Length; i++)
            {
                minHeap.Insert(ropes[i] * -1);
            }
            int ret = 0;

            while (!minHeap.IsEmpty())
            {
                int x = minHeap.RemoveTop() * -1;
                if (!minHeap.IsEmpty())
                {
                    int y      = minHeap.RemoveTop() * -1;
                    int newVal = (x + y) * -1;
                    minHeap.Insert(newVal);
                    ret += newVal * -1;
                }
            }
            return(ret);
        }
        /*
         *  Given a Knapsack of capacity G, and X items with weight W and values V,
         *  fill the sack with the max value possible.
         *  Items can be splitted in parts.
         */
        public static double Knapsack(int g, int[,] items)
        {
            int    itemCount = items.GetLength(0);
            double ret       = 0;

            if (itemCount == 0)
            {
                return(0);
            }
            if (itemCount == 1)
            {
                while (g > 0)
                {
                    ret += items[0, 0] / items[0, 1];
                    g--;
                }
                return(ret);
            }
            MaxHeap <double> mh = new MaxHeap <double>();

            for (int i = 0; i < itemCount; i++)
            {
                double valuePerWeight = (double)items[i, 0] / items[i, 1];
                while (items[i, 1]-- > 0)
                {
                    mh.Insert(valuePerWeight);
                }
            }
            while (g > 0 && !mh.IsEmpty())
            {
                double x = mh.RemoveTop();
                ret += x;
                g--;
            }
            return(ret);
        }