BacktrackerG's blog

By BacktrackerG, history, 2 days ago, In English

Hi,

I am trying to solve CSES Counting Towers and I'm having trouble finding what's wrong with my solution. I have described my process below, and it seems I am missing few combinations.

Let's call the number of combinations for 1xn towers a(n) and for 2xn towers b(n). Consider what the last blocks at the bottom of the tower are. We can have a 2xk block (k = 1 to n) at the end or one of the column having a 1xk block (k = 1 to n) at the end. In the first case, we will have b(n-k) variations. In the second case, the 1xk block can be on the left side and the right side. If one side has this 1xk block, then there are a(k) combinations of the other side. So our answer will be 2 * a(k). But we have double counted the combination of 2 1xk blocks. So actual answer is 2 * a(k) — 1. For each of these combinations of k blocks, there are b(n-k) variations.

Combining answers for both cases, we get b(n) = sum(k = 1 to n) 2 * a(k) * b(n-k). We can solve for a(k) to be = 1 << (k-1). Resulting in

b(n) = sum(k = 1 to n) (1 << k) * b(n-k) = 2 * b(n-1) + sum(k = 2 to n) (1 << k) b(n-k)

b(n) = 2 * b(n-1) + 2 * sum(k = 2 to n) (1 << k-1) b(n-k)
Use k = 1 + v and we find that the summation is just b(n-1)
So we get b(n) = 4 * b(n-1).

This is the wrong answer, and I am unable to find which combinations I am not counting. Please help! TIA!

Tags dp, cses
  • Vote: I like it
  • +3
  • Vote: I do not like it

»
2 days ago, # |
  Vote: I like it 0 Vote: I do not like it

Auto comment: topic has been updated by BacktrackerG (previous revision, new revision, compare).

»
46 hours ago, # |
Rev. 3   Vote: I like it 0 Vote: I do not like it

Example combination you're not counting:
n = 4, the left side is built using a 1x3 and a 1x1 block above it and the right side built using 2 1x2 blocks

Why this happens:

Spoiler (in case you want to try to think of the reason before reading)
How to fix it (UPD: I fixed the formula for b)
My solution

(I hope my explanation is clear enough)

Hope this helps!

  • »
    »
    45 hours ago, # ^ |
      Vote: I like it +3 Vote: I do not like it

    OMG, Thank you!! The example you gave was clear in pointing out my error. Unfortunately I did look up other solutions before I made this post hoping I'd find someone else with a similar approach, so I understood the code that you posted :/ .Thanks for the detailed response on how to fix my approach too, much appreciated.

    • »
      »
      »
      44 hours ago, # ^ |
        Vote: I like it +1 Vote: I do not like it

      Glad I could help! :)

      BTW CSES problems really helped me understand how to use DP, so if that's what you're trying to do, I'd advise you to solve as many as possible.

      PS. I think I found a way to optimise the solution I suggested above (the one based on your approach), I'll try it tomorrow and post it here if it works.

      • »
        »
        »
        »
        44 hours ago, # ^ |
          Vote: I like it +3 Vote: I do not like it

        I’m doing all the cses problems in order. Will stick to it!

  • »
    »
    27 hours ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    Here is the optimised solution:

    I've actually ended up changing what b is. Now b(n) is the number of combinations for 2xn towers if we start with width-1 blocks. Also, k is the height of the remaining tower. Still, the main idea of the solution is the same.

    Since a(n) = 1 << (n-1), we can see that:

    a(n) = 1 << (n-1) = (1 << (n-2)) * (1 << 1) = a(n-1) * 2
    

    Let's start with b. For each k, we have a(n-k) * a(n-k) combinations for the width-1 blocks and c(k) combinations for the rest of the tower, so sum(k = 0 to n-1) a(n-k) * a(n-k) * c(k) combinations in total.

    b(n) = sum(k = 0 to n-1) a(n-k) * a(n-k) * c(k)
         = (sum(k = 0 to n-2) a(n-k) * a(n-k) * c(k)) + a(n-(n-1)) * a(n-(n-1)) * c(n-1)
         = (sum(k = 0 to n-2) a(n-k-1) * 2 * a(n-k-1) * 2 * c(k)) + a(1) * a(1) * c(n-1)
         = 4 * (sum(k = 0 to (n-1)-1) a(n-k-1) * a(n-k-1) * c(k)) + 1 * 1 * c(n-1)
         = 4*b(n-1) + c(n-1)
    

    In c, after adding a 2x(n-k) block, we have b(k) + c(k) combinations for the rest of the tower, so sum(k = 0 to n-1) b(k) + c(k) combinations in total.

    c(n) = sum(k = 0 to n-1) b(k) + c(k)
         = (sum(k = 0 to n-2) b(k) + c(k)) + b(n-1) + c(n-1)
         = c(n-1) + b(n-1) + c(n-1)
         = 2*c(n-1) + b(n-1)
    

    These are correct as long as n-2 >= 0, so it won't work for n = 1. This will be our base case. There is only one way to split a 2x1 tower into width-1 blocks, and one way to split it into width-2 blocks, so b(1) = 1 and c(1) = 1.

    The code:

    Here's where it gets interesting: As you can see, this is basically the same as my previous solution. However, the idea is completely different.

    About time I explain my solution

    The states in these two solutions are actually the same. In each solution, we work level by level with two cases. In the previous solution, the two cases are the previous level either being split or not split, and this solution the cases are the current level either being split or not split. Because of this, their only difference is that in the previous solution, the n for both the base case and the value we print are smaller than the ones in this solution by 1.

»
45 hours ago, # |
  Vote: I like it +4 Vote: I do not like it

This was my thought process when I solved it. If you have a split block on previous layer, you can make 5 new configurations, where 1 will be non-split and 4 will be split. If you have a non-split block on previous layer, you can make 3 new configurations, 1 split and 2 non-split. (sorry for the poor handwriting and illustration, this is the figure I originally made when I solved the problem.)

My code (in Python) -

https://github.com/Grecil/pyCSES/blob/main/Dynamic%20Programming/Counting_Towers.py

  • »
    »
    44 hours ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    Thanks for the explanation. I had looked up others’ solutions before I made this post to check if anyone else made the same mistake as me but didn’t find any. Your diagram was clear and understandable don’t worry :)