Project Euler #122: Efficient exponentiation

Sort by

recency

|

13 Discussions

|

  • + 0 comments

    What surprised me the most was that it didn't require memoization.

  • + 0 comments

    100/- Points C++ Code

    #include <iostream>
    #include <vector>
    #include <map>
    
    //#define ORIGINAL
    
    // a single addition chain
    typedef std::vector<unsigned int> Chain;
    
    // iterative depth-first search of Brauer sequence
    bool search(Chain& chain, unsigned int exponent, unsigned int maxDepth)
    {
      // too deep ?
      if (chain.size() > maxDepth)
        return false;
    
      auto last = chain.back();
      for (size_t i = 0; i < chain.size(); i++)
      {
        //auto sum = chain[i] + last;
        auto sum = chain[chain.size() - 1 - i] + last; // try high exponents first => about twice as fast
        if (sum == exponent)
          return true;
    
        chain.push_back(sum);
        if (search(chain, exponent, maxDepth))
          return true;
    
        chain.pop_back();
      }
    
      return false;
    }
    
    // increase depth until a solution is found
    Chain findChain(unsigned int exponent)
    {
      // cached ? (needed for Hackerrank only)
      static std::map<unsigned int, Chain> cache;
      auto lookup = cache.find(exponent);
      if (lookup != cache.end())
        return lookup->second;
    
      // start iterative search
      Chain chain;
      unsigned int depth = 1;
      while (true)
      {
        // reset chain
        chain = { 1 };
        // a start search
        if (search(chain, exponent, depth))
          break;
    
        // failed, allow to go one step deeper
        depth++;
      }
    
      cache[exponent] = chain;
      return chain;
    }
    
    // print a single chain in Hackerrank format
    void print(const Chain& chain)
    {
      // number of multiplications
      std::cout << (chain.size() - 1) << std::endl;
      // print each multiplication
      for (size_t i = 1; i < chain.size(); i++)
      {
        // involved exponents
        auto sum  = chain[i];
        auto add1 = chain[i - 1];
        auto add2 = sum - add1;
    
        std::cout << "n";
        if (add1 > 1)
          std::cout << "^" << add1;
        std::cout << " * n";
        if (add2 > 1)
          std::cout << "^" << add2;
        std::cout << " = n^" << sum << std::endl;
      }
    }
    
    int main()
    {
    #ifdef ORIGINAL
    
      unsigned int sum = 0;
      // find all chains 2..200
      for (unsigned int exponent = 2; exponent <= 200; exponent++)
      {
        auto chain = findChain(exponent);
        // sum of all chains' lengths
        sum += chain.size();
      }
      std::cout << sum << std::endl;
    
    #else
    
      unsigned int tests;
      std::cin >> tests;
      while (tests--)
      {
        unsigned int exponent;
        std::cin >> exponent;
    
        // compute one chain (there might be different chains of the same length)
        auto chain = findChain(exponent);
        // append the exponent, which is not part of the chain yet
        chain.push_back(exponent);
        // and display
        print(chain);
      }
    
    #endif
    
      return 0;
    }
    
  • + 0 comments

    Is this a bruteforce problem-solving model? Can I see other's submission? I gave up :(

  • + 1 comment

    Was having trouble with the use of brauer chain (wasn't sure brauer chain necessarily contains one of the shortest chains for every , but it satisfies the input contraint here). Implemented some sort of breadth first search with deque and got Runtime Error #2.

    With a bit of tweaking, I found that for certain input range there must be a shortest chain starting with [1, 2, 4, 8, 16], and some smaller range [1, 2, 4, 8]. This reduces the queue significantly. Then it passed. Smells like cheating.

  • + 0 comments

    Hope this is not spoiler on contest. I think it is not, but if admins think it is, feel free to delete.

    Gotta say the expert who did handpick the test cases must be some kind of evil genius. Thanks. Got me delving bit deeper into this, since you just happened to pick some cases where Donald Knuth's power tree method fails to create the most optimal chain. There are not many numbers below 10000 where this method fails for creating the optimum chain. Well, Knuth tells in his book what are the numbers. Method itself is blazingly fast.

    BUT. Can anyone elaborate WHY power tree method fails on these numbers? My understanding on subject is not enough. Tried to think about it and cant see the reason.