General backtracking for a numbers' arrangement problem

Saw this problem on a Facebook post today:


To write a code for it, we can use DFS + backtracking. We can actually make it general enough so that we can solve it for:
1/ Any set of digits
2/ Broken into any group of numbers
3/ Looking for any target

The result for the puzzle above is this: 225 189 112

Code probably needs more boundary checks (overflows) as well as pruning of the search space, but for the most part it works. Code is down below, cheers, ACC.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Numerics;

namespace ProductNumbersTarget
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] digits = { 9, 2, 5, 2, 1, 1, 8, 2, 1 };
            Array.Sort(digits);
            BigInteger[] numbers = new BigInteger[3];
            for (int i = 0; i < numbers.Length; i++) numbers[i] = 0;
            BigInteger target = 4762800;

            FindProductArrangement(digits, new Hashtable(), numbers, 0, target);
        }

        //0: found
        //1: greater
        //-1: smaller
        static int FindProductArrangement(int[] digits,
                                          Hashtable usedIndex,
                                          BigInteger[] numbers,
                                          int rotatingIndex,
                                          BigInteger target)
        {
            BigInteger product = MultiplyNumbers(numbers);
            if (usedIndex.Count == digits.Length)
            {
                if (product == target)
                {
                    foreach (BigInteger n in numbers)
                        Console.Write("{0} ", n);
                    Console.WriteLine();
                    return 0;
                }
                else if (product > target) return 1;
                else return -1;
            }
            else if (product > target) return 1;

            bool productIsOver = false;
            bool[] indexOver = new bool[numbers.Length];
            for (int i = 0; i < digits.Length && !productIsOver; i++)
            {
                if (!usedIndex.ContainsKey(i))
                {
                    usedIndex.Add(i, true);
                    bool allProductOver = true;
                    for (int j = 0; j < numbers.Length; j++)
                    {
                        int index = (j + rotatingIndex) % numbers.Length;
                        if (indexOver[index]) continue;

                        BigInteger temp = numbers[index];
                        numbers[index] = 10 * numbers[index] + digits[i];
                        int retVal = FindProductArrangement(digits, usedIndex, numbers, (index + 1) % numbers.Length, target);
                        if (retVal == 0) return retVal;
                        indexOver[index] = (retVal > 0);
                        allProductOver &= indexOver[index];
                        numbers[index] = temp;
                    }
                    productIsOver = allProductOver;
                    usedIndex.Remove(i);
                }
            }

            return -1;
        }

        static BigInteger MultiplyNumbers(BigInteger[] numbers)
        {
            BigInteger retVal = 1;
            foreach (BigInteger n in numbers)
                if (n > 0) retVal *= n;
            return retVal;
        }
    }
}

Comments

Popular posts from this blog

Advent of Code - Day 6, 2024: BFS and FSM

Golang vs. C#: performance characteristics (simple case study)

Advent of Code - Day 7, 2024: Backtracking and Eval