Beispiel #1
0
        public override long CalculateTotalCoins(int valueToCalculate, long[] arr, CalcState parentState = null, int depth = 1)
        {
            #if DEBUG
            if (valueToCalculate <= 0)
            {
                throw new Exception($"Unexpected valueToCalculate - {valueToCalculate}");
            }

            if (coin.Next != null)
            {
                throw new Exception("Root node is supposed to be singleton");
            }

            if (arr.Length <= valueToCalculate)
            {
                throw new Exception("passed in array is supposed to be >= max valueToCalculate");
            }

            if (parentState != null)
            {
                throw new Exception("Expected parentState to be null on calling root node");
            }

            Grid.StartDebug(this, valueToCalculate);
            #endif

            // we are singleton - e.g., '9'  if we get hit by '18' then
            // there are 2 coins we can make ...
            if (valueToCalculate % Head == 0)
            {
                int myCoins = valueToCalculate / Head;

                // keep tally in global record;
                arr[myCoins]++;

#if DEBUG
                Grid.Debug(this, myCoins, 1);

                Grid.EndDebug(this);
#endif
                return(1 + GetChildren().Sum(x =>
                                             x.CalculateTotalCoins(valueToCalculate, arr, new CalcState(myCoins, myCoins - 1, 1), depth + 1)));
            }
            return(0);
        }
        /// <summary>
        /// Given an array from our parent indicating how many Total coins the parent
        /// has produced - we have a relatively simple way of calculating how many
        /// total coins we will produce.
        ///
        /// We need three items :
        ///
        /// A) the parent array of total coins produced for each combo
        /// B) the number of coins to subtract for every combination
        /// C) the number of combinations to subtract every time we add one of our coins
        ///
        /// B) and C) are the same for every input value.
        ///
        /// To derive A -> Every time we ADD our unit to the previous (parent) combination
        /// we are adding one coin = +1 but subtracting "UNIT coins/bottom UNIT".
        /// so, e.g., if we are 'head' in the combination (4,1) then we subtract 3 coins
        /// from each entry in the input array to reflect the fact we are reducing by 3 overall.
        /// if  we are 'head' in the combination (8,4) then we subtract 1 coin.
        ///
        /// so UNIT/HEAD_UNIT - 1 is the number of coins to remove from the input array
        /// when we add one of our UNITS (B)
        ///
        /// Number of combinations we need to generate is derived by how many combinations
        /// does our parent produce for one of our Units.
        ///
        /// E.g., say we add ONE of our units to the set of parent combinations
        /// we will be adding just one combination to the total, but, as the PARENT
        /// combinations are already factored into the output - we need to make sure we do not
        /// duplicate them - so so we subtract however many there are.
        ///
        /// e.g., if we are '4' in 1,2,4 ... then when we are triggered first time
        /// when value is '7' we will be triggered with 3 # combinations from 1,2
        /// - (5,1)=6,(3,2)=5,(1,3)=4 ... we are adding a new combination
        /// (1,1,1)=3 so the total set will contain 4 combinations - but we
        /// have already output 3 - so, in this example, the difference in combo numbers for adding a new Unit (C)
        /// will be 3-1 = 2.
        ///
        /// We calculate the 'C' the first time we are triggered based on the
        /// number of combos from our parent - easy.
        ///
        /// Our parent provides us with #of combinations, the max-number of coins and the 'step' between each coin
        ///
        /// We will be transforming that into an array where each row provides our corresponding number of combinations.
        ///
        /// Because each new coin -> 1 to (Value/Units) -> reduces the combination set and reduces the maximum number
        /// we get a triangular output, where each row is number of coins
        ///
        /// E.g., if provided with following array indicating (45-26)=19 combinations and top one has 45 coins.
        ///
        /// 45,
        /// 44
        /// 43,
        /// 42,
        /// 41
        /// ...
        /// 26
        ///
        /// we can convert this to following downward sloping triangle
        /// 45
        /// 44
        /// 43	43
        /// 42	42
        /// 41	41
        /// 40	40	40
        /// 39	39	39
        /// 38	38	38
        /// 37	37	37	37
        /// 36	36	36	36
        /// 35	35	35	35
        /// 34	34	34	34	34
        /// 33	33	33	33	33
        /// 32	32	32	32	32
        /// 31	31	31	31	31	31
        /// 30	30	30	30	30	30
        /// 29	29	29	29	29	29
        /// 28	28	28	28	28	28	28
        /// 27	27	27	27	27	27	27
        /// 26	26	26	26	26	26	26
        /// 25	25	25	25	25	25	25	25
        ///     24	24	24	24	24	24	24
        ///         23	23	23	23	23	23
        ///             22	22	22	22	22	22
        ///                 21	21	21	21	21
        ///                     20	20	20	20
        ///                         19	19	19	19
        ///                             18	18	18
        ///                                 17	17
        ///                                     16	16
        ///                                         15
        ///
        /// where each new column is a new combination,
        /// number of new columns is given by Value/Units,
        /// the top downward slope is given by (B) - no coins to subtract for each combination
        /// and length of each successive column is (C) minus previous length
        ///
        /// and then we can convert this to e.g,.
        ///
        /// 45 = 1
        /// 44 = 1
        /// 43 = 2
        /// 42 = 2
        /// etc.,
        ///
        /// And add that to our state - indicating that, e.g., there are 2 combinations where total coins is '43' etc.,
        ///
        /// We could iterate over each column to do this - but this would be inefficient.
        ///
        /// so instead, we do it directly - by calculating the height of the whole triangle.
        /// incrementing the no_of_combos until we reach the mid-point (25) in example above
        /// and then decrementing the no_of_combos after that until we reach the end point (15).
        ///
        /// It is grim - but efficient ...
        ///
        ///
        /// </summary>
        /// <param name="valueToCalculate"></param>
        /// <param name="arr"></param>
        /// <param name="parentState"></param>
        /// <param name="depth"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public override long CalculateTotalCoins(int valueToCalculate, long[] arr, CalcState parentState = null, int depth = 1)
        {
            #if DEBUG
            if (depth != this.Depth)
            {
                throw new Exception("Calc tree out of synch somehow ");
            }

            if (valueToCalculate <= 0)
            {
                throw new Exception($"Unexpected valueToCalculate - {valueToCalculate}");
            }
            #endif

            if (differenceInParentComboNumberForEachCoin == -1)
            {
                // every time we add a new coin at this level we have same as previous level -
                // _minus_ the number of parent combinations it takes to make one of our coins.
                // (given by GetMaxCombinationsForValue - where SumOfUnits is our minimum trigger value).
                // plus one - because this is a new combination.
                differenceInParentComboNumberForEachCoin = parent.GetMaxCombinationsForValue(SumOfUnits) - 1;
            }

            if (noCoinsToSubtractForEachUnit == -1)
            {
                noCoinsToSubtractForEachUnit = (Head / GetRootUnit()) - 1;

                if (noCoinsToSubtractForEachUnit < 1)
                {
                    throw new ArgumentException("noCoinsToSubtractForEachUnit expected to be >=1");
                }
            }

            // every time we have a new coin we reduce our number of coins by
            // noCoinsToSubtractForEachUnit - (moving our triangle coin columns down by X)
            // but we also have less combinations to add ... this represents our net shift).
            if (decrementInTotalCoinsForEachCoin == -1)
            {
                decrementInTotalCoinsForEachCoin = noCoinsToSubtractForEachUnit - differenceInParentComboNumberForEachCoin;
            }

#if DEBUG
            Grid.StartDebug(this, valueToCalculate);
#endif

            if (valueToCalculate - SumOfUnits >= 0)
            {
                var thisNumberCombinations = ((valueToCalculate - SumOfUnits) / Head) + 1;

                int cnt = 0;
                int max = -1;
                int min = int.MaxValue;
                int ourStartingNoCoins = parentState.MaxParentCoins - noCoinsToSubtractForEachUnit;

                // our first column - to the right-angled part of triangle height = same as height of parentState
                // minus the decrementInTotalCoinsForEachCoin
                int ourHeight = (parentState.NumberCombinations - differenceInParentComboNumberForEachCoin);

                if (ourHeight <= 0)
                {
                    throw new Exception($"Invalid height of triange - {ourHeight}");
                }

                foreach (var(triangleRow, number) in new CoinTriangle(ourStartingNoCoins,
                                                                      ourHeight, thisNumberCombinations,
                                                                      noCoinsToSubtractForEachUnit, decrementInTotalCoinsForEachCoin))
                {
                    if (max == -1)
                    {
                        max = triangleRow;
                    }
                    min = triangleRow;
                    arr[triangleRow] += number;

#if DEBUG
                    Grid.Debug(this, triangleRow, number);
#endif
                    if (number > 0)
                    {
                        cnt++;
                    }
                }

#if DEBUG
                Grid.EndDebug(this);
#endif

                var ourState = new CalcState(max, min, cnt);
                return(cnt + GetChildren().Sum(x => x.CalculateTotalCoins(valueToCalculate, arr, ourState, depth + 1)));
            }

            return(0);
        }
Beispiel #3
0
        public override long CalculateTotalCoins(int valueToCalculate, long[] arr, CalcState parentState = null,
                                                 int depth = 1)
        {
#if DEBUG
            if (depth != 2)
            {
                throw new Exception("CalculationNodeVector should only be called when depth == 2");
            }

            if (parentState.NumberCombinations != 1)
            {
                throw new Exception("Expecting scalar from root node");
            }

            if (noCoinsToSubtractForEachUnit == -1)
            {
                noCoinsToSubtractForEachUnit = (Head / GetRootUnit()) - 1;

                if (noCoinsToSubtractForEachUnit < 1)
                {
                    throw new ArgumentException("noCoinsToSubtractForEachUnit expected to be >=1");
                }
            }

            Grid.StartDebug(this, valueToCalculate);
#endif


            long cnt = 0;
            if (valueToCalculate - SumOfUnits >= 0)
            {
                var max        = -1;
                var min        = -1;
                var startValue = parentState.MaxParentCoins;
                for (int i = 0; i < ((valueToCalculate - SumOfUnits) / Head) + 1; i++)
                {
                    startValue -= noCoinsToSubtractForEachUnit;
                    if (max == -1)
                    {
                        max = startValue;
                    }
                    min = startValue;
                    arr[startValue]++;

#if DEBUG
                    Grid.Debug(this, startValue, 1);
#endif
                    cnt++;
                }

#if DEBUG
                Grid.EndDebug(this);
#endif

                var ps = new CalcState(max, min, (int)cnt);
                foreach (var c in GetChildren())
                {
                    cnt += c.CalculateTotalCoins(valueToCalculate, arr, ps, depth + 1);
                }
            }


            return(cnt);
        }
Beispiel #4
0
 public abstract Int64 CalculateTotalCoins(int valuetoCalculate, Int64[] arr, CalcState parentState = null, int depth = 1);