- James S. Plank
- October, 2011
- Latest Revision, October, 2012

Here's the Problem Statement.

This is a graph problem. The first thing to realize is that since the carrots
are placed at every multiple of 1,000,000,007, we can reduce the problem to
taking the rabbit's position mod 1,000,000,007, and if the result is zero, then
the rabbit is on a carrot. That number is unwieldy, so let's call it *BP*
(for "big prime").

When the rabbit is at position *x*, he/she can jump to two positions:
*(4x+3)%BP* and *(8x+7)%BP*. You can view each position as a node
on a graph, and each jump to a new position as an edge. The problem then
becomes to find the shortest path to node 0. The graph is unweighted, so
your job is to solve an unweighted shortest path problem using
breadth-first search.

There is a little subtlety, which is common to some shortest path problems --
the graph is potentially huge! There are *BP* potential nodes on this
graph, so we certainly cannot build it and hold it in memory. However,
we don't have to hold the entire graph in memory. Instead, we build it incrementally
while we do the shortest path calculation. Recall how unweighted shortest path
works:

- Remove a node from the queue.
- If this node is our target node (node 0 in this case), then you're done.
- Otherwise, traverse the node's adjacency list, and for all edges to nodes that have not been visited and are not on the queue, push them onto the queue.

There's nothing in this algorithm that says you have to build the graph before-hand. Instead, you can create the adjacency list when you visit a node, and create the new nodes at that point if you need to.

Let's build a solution. We want each node to have two values: its id and its
*distance*, which is the minimum number of
hops from **init** to the node. We could define a **class** for nodes, and
a queue of nodes for the breadth-first search. However, to make my programming
easier, I'm simply going to maintain two queues of integers. The first queue
holds node id's and the second holds distances. I'm going to declare them as
**deque's** since that data structure allows you do append to the end and
delete the beginning in constant time.

We start by pushing **init** onto our breadth-first search queue. This
really means two **push_back()** operations -- pushing **init** onto our
id queue and zero onto our distance queue.
We'll exemplify with example #1 from the topcoder problem,
where the rabbit starts at 281,250,001. In the pictures below, I'll draw
the graph so far, and the queue's **id** and **distance**:

Now, we process the queue as in the bulleted list above. We remove the first
element from **ids** and **distances**. We test whether the id is zero.
If it is, we're done. It's not, so we calculate its two edges:

For each of those edges, we push them on the queue with a distance of one:

I want to stress, our program does not store the graph. That's only drawn to
help you visualize the solution. We only hold the two **deques**.
We next process id 125,000,000 with a distance of one. Here are its edges:

That looks promising. Let's push these new nodes onto **ids** and **distances**.

Next we work on 250,000,001, whose distance is one. Here's the new graph:

You'll note that node zero is on the queue **ids** twice. We'll deal with that
later. However, it should give you a clue about how this problem does not blow
up exponentially.
If *y = 4x+3*
and *z = 8x+7*, then:

Whatever, we'll deal with that later. Let's process the next node on the queue -- 500,000,003:

When we process the next node, it's id is zero, so we're done. We return the distance of two.

int CarrotJumping::theJump(int init) { deque <int> ids; deque <int> distances; int node; int distance; ids.push_back(init); distances.push_back(0); while (1) { node = ids[0]; distance = distances[0]; ids.pop_front(); distances.pop_front(); cout << "Processing node " << node << " with a distance of " << distance << endl; if (node == 0) return distance; ids.push_back((node*4+3)%1000000007); distances.push_back(distance+1); ids.push_back((node*8+7)%1000000007); distances.push_back(distance+1); } } |

That's a nice and simple BFS. Let's run it on the first two examples (my driver program
is in **Carrot-Main.cpp**, which includes **CarrotJumping.cpp** and compiles in
the topcoder examples:

UNIX>Well, it gets the correct answer with both examples, but the node "-44967367" suggests that using integers will not work. Think about it:cp Carrot-Jumping-1.cpp CarrotJumping.cppUNIX>g++ Carrot-Main.cppUNIX>a.out 0Processing node 125000000 with a distance of 0 Processing node 500000003 with a distance of 1 Processing node 0 with a distance of 1 1 UNIX>a.out 1Processing node 281250001 with a distance of 0 Processing node 125000000 with a distance of 1 Processing node -44967267 with a distance of 1 Processing node 500000003 with a distance of 2 Processing node 0 with a distance of 2 2 UNIX>

UNIX>The problem is all of those duplicate nodes on the deques. You can solve that problem by maintaining acp Carrot-Jumping-2.cpp CarrotJumping.cppUNIX>g++ Carrot-Main.cppUNIX>a.out 0Processing node 125000000 with a distance of 0 Processing node 500000003 with a distance of 1 Processing node 0 with a distance of 1 1 UNIX>a.out 1Processing node 281250001 with a distance of 0 Processing node 125000000 with a distance of 1 Processing node 250000001 with a distance of 1 Processing node 500000003 with a distance of 2 Processing node 0 with a distance of 2 2 UNIX>a.out 2Processing node 18426114 with a distance of 0 Processing node 73704459 with a distance of 1 Processing node 147408919 with a distance of 1 Processing node 294817839 with a distance of 2 Processing node 589635679 with a distance of 2 Processing node 589635679 with a distance of 2 Processing node 179271352 with a distance of 2 Processing node 179271352 with a distance of 3 Processing node 358542705 with a distance of 3 Processing node 358542705 with a distance of 3 ....You CNTL-C out of this and try:UNIX>a.out 2 | tail -n 1....And this takes forever.

int CarrotJumping::theJump(int init) { deque <long long> ids; deque <int> distances; set <long long> nodes; long long node, newnode; int distance; ids.push_back(init); distances.push_back(0); while (1) { node = ids[0]; distance = distances[0]; ids.pop_front(); distances.pop_front(); if (node == 0) return distance; newnode = (node*4+3)%1000000007; if (nodes.find(newnode) == nodes.end()) { ids.push_back(newnode); distances.push_back(distance+1); nodes.insert(newnode); } newnode = (node*8+7)%1000000007; if (nodes.find(newnode) == nodes.end()) { ids.push_back(newnode); distances.push_back(distance+1); nodes.insert(newnode); } } } |

That works for examples 2 through 4, and since example 4 takes a little time, we check it to see that it runs within 2 seconds -- we're good:

UNIX>We now need to handle what happens when our rabbit jumps 100001 times. He quits, and we return -1. That's an easy check ofcp Carrot-Jumping-3.cpp CarrotJumping.cppUNIX>g++ Carrot-Main.cppUNIX>a.out 258 UNIX>a.out 3478 UNIX>a.out 4100000 UNIX>time a.out 4100000 0.930u 0.020s 0:00.95 100.0% 0+0k 0+0io 0pf+0w UNIX>

... if (distance == 100001) return -1; /* This is the only new line */ ... |

It succeeds on example 5:

UNIX>Time to submit? Well now is a good time to think about conditions which may trip you up. Can you think of any? I can tell you that these few lines should be a little bit of a red flag:cp Carrot-Jumping-4.cpp CarrotJumping.cppUNIX>g++ Carrot-Main.cppUNIX>a.out 5-1 UNIX>

... while (1) { node = ids[0]; distance = distances[0]; ... |

Think to yourself: "Can that loop really be infinte?" and "Could the size of **ids** or
**distances** be zero?" I think that the answer to the first one is "no" -- example
5 shows the longest time it will take. How about the second question. Could we run out
of nodes? Maybe. Maybe our graph has nothing but cycles. If that's the case, our
rabbit is going to be jumping around infinitely, and more importantly, **ids** and
**distances** will become empty. So, let's fix it by testing **ids**, and if
it's empty, we return -1.

The final code is in
**Carrot-Jumping-5.cpp**. As it turns out,
I've put case 6 into **Carrot-Main.cpp**, which sets *init* to 1,000,000,006,
where *(4x+3)%BP* equals *x*. We need that test for the program to work in
this case. (When I first did this problem, that case is the one that tripped me up....).

The final program is below:

#include <string> #include <deque> #include <set> #include <iostream> #include <cstdio> #include <cstdlib> using namespace std; class CarrotJumping { public: int theJump(int init); }; int CarrotJumping::theJump(int init) { deque <long long> ids; deque <int> distances; set <long long> nodes; long long node, newnode; int distance; ids.push_back(init); distances.push_back(0); while (1) { if (ids.size() == 0) return -1; node = ids[0]; distance = distances[0]; ids.pop_front(); distances.pop_front(); if (distance == 100001) return -1; if (node == 0) return distance; newnode = (node*4+3)%1000000007; if (nodes.find(newnode) == nodes.end()) { ids.push_back(newnode); distances.push_back(distance+1); nodes.insert(newnode); } newnode = (node*8+7)%1000000007; if (nodes.find(newnode) == nodes.end()) { ids.push_back(newnode); distances.push_back(distance+1); nodes.insert(newnode); } } } |