Beispiel #1
0
        /* PROBLEM DESCRIPTION:
         * We have a set budget, that we need to split between agents who can divide their time between a set of actions, to maximize the resulting gain.
         *
         * OUTPUT:
         * selections[] is the selected action for each agent
         * if interpSet is >= 0, then it denotes the only agent that splits its time between actions: (1 - interpT) time doing selections[interpSet] and interpT time doing interpTarget
         *
         * NOTE: will clobber costs and gains arrays
         */
        public static void FindBestBudgetSplit(double[] costs, double[] gains, int l, int n, double budget, out int[] selections, out int interpSet, out double interpT, out int interpTarget)
        {
            int[] hulls    = new int[n * l];
            int[] hullends = new int[n];

            double[] scratch = new double[l];
            for (int i = 0; i < n; ++i)
            {
                hullends[i] = i * l + FindUpperIncreasingConvexHullPoints(costs, gains, hulls, i * l, l, scratch);
            }

            DoubleMaxHeap <int> pq = new DoubleMaxHeap <int>();

            int[] cursors = new int[n];

            for (int i = 0; i < n; ++i)
            {
                int c = i * l;
                cursors[i] = c;
                budget    -= costs[c];
                if ((c + 1) < hullends[i])
                {
                    pq.Push((gains[c + 1] - gains[c]) / (costs[c + 1] - costs[c]), i);
                }
            }

            interpSet    = -1;
            interpT      = 0;
            interpTarget = -1;

            while (pq.Count > 0 && budget > 0)
            {
                int i = pq.TopValue;
                pq.Pop();

                int    c         = cursors[i];
                double deltacost = costs[c + 1] - costs[c];
                if (deltacost < budget)
                {
                    budget -= deltacost;

                    cursors[i] = ++c;
                    if ((c + 1) < hullends[i])
                    {
                        pq.Push((gains[c + 1] - gains[c]) / (costs[c + 1] - costs[c]), i);
                    }
                }
                else
                {
                    interpSet    = i;
                    interpT      = budget / deltacost;
                    interpTarget = hulls[c + 1] - i * l;
                    break;
                }
            }

            selections = new int[n];
            for (int i = 0; i < n; ++i)
            {
                selections[i] = hulls[cursors[i]] - i * l;
            }
        }
Beispiel #2
0
        // effects with the same cooldown and the same nonnegative bucket number will not be triggered simultaneously
        // otherwise, we naively engage each cooldown ASAP
        public static FightDivision ComputeNaive(SpecialEffect[] effects, double fightLength, int[] buckets = null)
        {
            KeyValuePair <SpecialEffect, int>[] effectsAndBuckets = new KeyValuePair <SpecialEffect, int> [effects.Length];
            for (int i = 0; i < effects.Length; ++i)
            {
                effectsAndBuckets[i] = new KeyValuePair <SpecialEffect, int>(effects[i], (buckets != null) ? buckets[i] : -1);
            }

            Array.Sort(effectsAndBuckets, new SpecialEffectComparer());

            double lastCooldown = double.PositiveInfinity;
            int    lastBucket   = -1;
            double bucketOffset = 0;

            DoubleMaxHeap <int> pq = new DoubleMaxHeap <int>();

            for (int i = 0; i < effectsAndBuckets.Length; ++i)
            {
                effects[i] = effectsAndBuckets[i].Key;

                if (effects[i].Cooldown != lastCooldown)
                {
                    lastCooldown = effects[i].Cooldown;
                    lastBucket   = -1;
                    bucketOffset = 0;
                }

                if (effectsAndBuckets[i].Value != lastBucket)
                {
                    lastBucket   = effectsAndBuckets[i].Value;
                    bucketOffset = 0;
                }

                double offset = bucketOffset;
                if (lastBucket >= 0)
                {
                    bucketOffset += effects[i].Duration;
                }

                pq.Push(-offset, i << 1);
            }

            pq.Push(-fightLength, -1);

            Dictionary <int, double> effectDurations = new Dictionary <int, double>();

            int    effectMask = 0;
            double time       = 0;

            for (; ;)
            {
                double nextTime = -pq.TopKey;
                int    id       = pq.TopValue;
                pq.Pop();

                if (nextTime != time)
                {
                    double v = 0;
                    effectDurations.TryGetValue(effectMask, out v);
                    effectDurations[effectMask] = v + nextTime - time;
                }

                time = nextTime;

                if (id < 0)
                {
                    break;
                }

                int i = id >> 1;

                if ((id & 1) == 0)
                {
                    effectMask |= 1 << i;
                    pq.Push(-(time + effects[i].Duration), (i << 1) | 1);
                }
                else
                {
                    effectMask &= ~(1 << i);
                    pq.Push(-(time + effects[i].Cooldown - effects[i].Duration), i << 1);
                }
            }

            List <KeyValuePair <int, double> > effectDurationsList = new List <KeyValuePair <int, double> >();

            effectDurationsList.AddRange(effectDurations);
            effectDurationsList.Sort((a, b) => a.Key - b.Key);

            int[]    effectMasks = new int[effectDurations.Count];
            double[] fractions   = new double[effectDurations.Count];
            {
                int i = 0;
                foreach (KeyValuePair <int, double> effectDuration in effectDurationsList)
                {
                    effectMasks[i] = effectDuration.Key;
                    fractions[i]   = effectDuration.Value / fightLength;
                    ++i;
                }
            }

            return(new FightDivision(effects, fractions, effectMasks));
        }
Beispiel #3
0
        /* PROBLEM DESCRIPTION:
         * We have a set budget, that we need to split between agents who can divide their time between a set of actions, to maximize the resulting gain.
         * 
         * OUTPUT:
         * selections[] is the selected action for each agent
         * if interpSet is >= 0, then it denotes the only agent that splits its time between actions: (1 - interpT) time doing selections[interpSet] and interpT time doing interpTarget
         * 
         * NOTE: will clobber costs and gains arrays
         */
        public static void FindBestBudgetSplit(double[] costs, double[] gains, int l, int n, double budget, out int[] selections, out int interpSet, out double interpT, out int interpTarget)
        {
            int[] hulls = new int[n * l];
            int[] hullends = new int[n];

            double[] scratch = new double[l];
            for (int i = 0; i < n; ++i)
                hullends[i] = i * l + FindUpperIncreasingConvexHullPoints(costs, gains, hulls, i * l, l, scratch);

            DoubleMaxHeap<int> pq = new DoubleMaxHeap<int>();
            int[] cursors = new int[n];

            for (int i = 0; i < n; ++i)
            {
                int c = i * l;
                cursors[i] = c;
                budget -= costs[c];
                if ((c + 1) < hullends[i])
                    pq.Push((gains[c + 1] - gains[c]) / (costs[c + 1] - costs[c]), i);
            }

            interpSet = -1;
            interpT = 0;
            interpTarget = -1;

            while (pq.Count > 0 && budget > 0)
            {
                int i = pq.TopValue;
                pq.Pop();

                int c = cursors[i];
                double deltacost = costs[c + 1] - costs[c];
                if (deltacost < budget)
                {
                    budget -= deltacost;
                    
                    cursors[i] = ++c;
                    if ((c + 1) < hullends[i])
                        pq.Push((gains[c + 1] - gains[c]) / (costs[c + 1] - costs[c]), i);
                }
                else
                {
                    interpSet = i;
                    interpT = budget / deltacost;
                    interpTarget = hulls[c + 1] - i * l;
                    break;
                }
            }

            selections = new int[n];
            for (int i = 0; i < n; ++i)
                selections[i] = hulls[cursors[i]] - i * l;
        }