Playing-with-Problems-II
DevelopmentTutorial

Playing with Problems II



Continuing on last week's theme of "playing with problems" let's try it out with another fun problem: opening doors!

There are n closed doors in a long corridor, numbered 1 to n. A person walks through and opens each door. Another person walks through and closes every alternate door. This continues with the i-th person toggling the state of every i-th door. How many doors are left open after the nth person is done?


Well the problem is simple enough to understand, so we can whip out our editors and dash off a solution in no time!
This, as you know from my previous blog is a mistake...

Rushing to a Solution


If, as we saw in the blog, we rush to the solution we may implement a solution like this:
[objc]
int doors_open(int n) {
int doors[n];
std::fill(doors, doors+n, 0); /* start with closed doors */
for(int i = 1;i <= n;i++) {
int p = i;
while (p <= n) {
doors[p-1] = !doors[p-1]; /* toggle */
p += i;
}
}
return std::count(doors, doors+n, 1);
}
[/objc]
Then we'll spend time trying to optimize it (let's use a bitset!) and use all the technical wizardry and deep knowledge we are so good at. However, our solution will most likely remain O(n log(n)).

Playing with the Problem


Instead, if we play around with the problem for a bit we will begin to notice a pattern -


For 1 door - Doors open: 1
For 2 doors - Doors open: 1
For 3 doors - Doors open: 1
For 4 doors - Doors open: 1, 4
For 5 doors - Doors open: 1, 4


For 6 door - Doors open: 1, 4
For 7 doors - Doors open: 1, 4
For 8 doors - Doors open: 1, 4
For 9 doors - Doors open: 1, 4, 9
For 10 doors - Doors open: 1, 4, 9


Now we can clearly see a pattern. Why does this happen? Well, play with the problem for a bit and you will figure it out!
Once we understand it the pattern, the solution becomes so much simpler!
[objc]
int doors_open(int n) {
return std::sqrt(n); /* neat huh? */
}
[/objc]

The Explanation


If you've played with the problem and still can't figure it out - I'll explain it for you. But before you read ahead, do promise you've tried it out yourself.
Ok so if we think about it, door 1 will be touched only by person 1, door 2 will be touched by person 1 and 2, door 3 will be touched by person 1 and 3, and so on. In general door i will be touched by all the divisors of i upto i.
[text]
Door 6 Door 9
| |
1 2 3 6 1 3 9
[/text]
Now every divisor has a corresponding "pair"

image7


which means that whatever x does, y will simply undo. Therefore the door state will not change.
The only time we don't have a "pair" is when x = y i.e. the number is a square of another number. Therefore only the perfect squares (1,4,9,16,...) are left open. So all we need to know is how many perfect squares are there < n which is sqrt(n).

Conclusion


As with my last post, I am hoping to show you how important (and fun) it can be to play with the problems given to you before trying to find a solution. This is a hard but excellent habit to cultivate and will stand you in good stead through your career.