The first topics that I wish to discuss are simulation and brute forcing. Surprisingly, many problems can be solved just by simulating the environment described in the problem and brute forcing all cases [CS02-7]. Meaning, we do not necessarily require a complex algorithms to solve the problems and it suffices to know that basic of the language that we are using, which we already did in our previous note.

Because there isn’t a definite concept, definition, and theorems for these concept, let’s see what they are through example problems.

0.1.1 Simulation

For our first simulation problem, let’s solve 2018 USACO First Bronze Problem 1.

Exercise 0.1.1: 2018 USACO First Bronze Problem 1

(Problem Statement)

Say there are three buckets with capacity \(c_1\), \(c_2\), and \(c_3\) respectively. The buckets are initially filled with \(m_1\), \(m_2\), and \(m_3\) amount of milk. A farmer wants to pour milk from bucket \(1\) to \(2\), \(2\) to \(3\), \(3\) to \(1\), \(1\) to \(2\), and so on for hundred times where each pour ends if the bucket being poured is empty or the bucket receiving the milk is full. How much milk is left in each bucket after the \(100^\text {th}\) pour?

Solution.

To solve this problem, we can literally simulate the process of pouring and receiving milk. Notice that in each pour, we stop if and only if a bucket is empty or a bucket is full. Then, we iterate the same process. Due to this nature, we can define a function that takes in the amount of milk in two buckets and the capacity of the bucket receiving to update the amount of milk in each bucket after the pour.

void mix(int& a, int& b, int& x) { 
    if (a + b <= x) { 
        b = a + b; 
        a = 0; 
    } else { 
        a = a + b - x; 
        b = x; 
    } 
}

Here, \(a\) and \(b\) are the amount of milk in two buckets and \(x\) is the capacity of the bucket with \(b\) amount of milk. If the bucket receiving has the capacity to receive all milk, i.e. \(a + b \leq x\), then our new \(b\) will be \(a + b\) while the bucket with originally \(a\) amount of milk is empty. Notice that we want to update \(b\) first before fixing \(a\) to zero.

The other case is when we cannot pour all milk when mixing, i.e. \(a + b > x\). In that case, our new \(a\) will be \(a + b - x\) and \(b = x\). Also notice that we want to update \(a\) first since we don’t want \(a = a\). Applying this function \(100\) times, we can successfully simulate the environment in the problem.

Code 0.1.2: CS0202.26057-01

1#include <cstdio> 
2#include <iostream> 
3using namespace std; 
4 
5void mix(int& a, int& b, int& x) { 
6    if (a + b <= x) { 
7        b = a + b; 
8        a = 0; 
9    } else { 
10        a = a + b - x; 
11        b = x; 
12    } 
13} 
14 
15int main() { 
16    freopen("mixmilk.in", "r", stdin); 
17    freopen("mixmilk.out", "w", stdout); 
18 
19    int c1, c2, c3, m1, m2, m3; 
20    cin >> c1 >> m1 >> c2 >> m2 >> c3 >> m3; 
21 
22    for (int i = 0; i < 33; i++) { 
23        mix(m1, m2, c2); 
24        mix(m2, m3, c3); 
25        mix(m3, m1, c1); 
26    } 
27    mix(m1, m2, c2); 
28 
29    cout << m1 << "\n" << m2 << "\n" << m3 << "\n"; 
30 
31    return 0; 
32}

This solves the problem!

As you can see from the example above, we simulate the environment described to solve the problem. Below is another example for simulation.

Exercise 0.1.3: 2017 USACO Open Bronze Problem 1

(Problem Statement)

A farmer and a cow is in a number line with position \(x, y > 0\) respectively. The farmer will move in zig zag from \(x\) and doubling the distance from \(x\) in each move. For instance, the farmer moves from \(x\) to \(x+1\) to \(x-2\) to \(x+4\) and so on. What is the total distance that the farmer moves until reaching the cow?

Solution.

To solve this problem, we can simulate the situation where the farmer is moving. However before doing that, let’s shift the position of the initial position of the farmer and the cow by \(x\) to make our lives easier.

int z = y - x;
With this, the position of the farmer is \(0\) and the cow is \(z\). Note that this is possible because the distance between them remains unchanged. From here, we can separate the cases into two case: \(z < 0\) and \(z > 0\). \(z\) can be negative since it is possible that \(y < x\).

For integer \(n \geq 0\), we can see that the farmer won’t reach \(2^{2n}\) for some \(n\) if \(z > 0\) and the farmer will not reach \(2^{2n+1}\) for some \(n\) if \(z < 0\). Using this, we can know that the distance that the farmer will move if \(z > 0\) can be represented as the following where \(n\) is the minimum value that the farmer will stop moving. \begin{align*} &\quad \ 1 + (1 + 2) + (2 + 4) + \cdots + \left ( 2^{2n-2} + 2^{2n-1} \right ) + \left ( 2^{2n-1} + z \right ) \\ &= 2 \left ( 1 + 2 + 4 + \cdots + 2^{2n-1} \right ) + z = 2 \left ( 2^{2n} - 1 \right ) + z \end{align*}

Similarly using geometric sequence, we can apply the same idea for \(z < 0\). \begin{align*} &\quad \ 1 + (1 + 2) + (2 + 4) + (4 + 8) \cdots + \left ( 2^{2n-1} + 2^{2n} \right ) + \left ( 2^{2n} + z \right ) \\ &= 2 \left ( 1 + 2 + 4 + \cdots + 2^{2n} \right ) + z = 2 \left ( 2^{2n+1} - 1 \right ) + z \end{align*}

Applying it with C++, we can use the while loop to find when to stop and conditions to determine which value to output.

Code 0.1.4: CS0202.26057-02

1#include <cstdio> 
2#include <iostream> 
3#include <cmath> 
4using namespace std; 
5 
6int main() { 
7    freopen("lostcow.in", "r", stdin); 
8    freopen("lostcow.out", "w", stdout); 
9 
10    int x, y; 
11    cin >> x >> y; 
12    int z = y - x; 
13 
14    int n = 0; 
15    if (z > 0) { 
16        while (pow(2,2*n) < z) { 
17            n++; 
18        } 
19        cout << 2*(pow(2,2*n) - 1) + z << "\n"; 
20    } else if (z < 0) { 
21        while (pow(2,2*n+1) < -z) { 
22            n++; 
23        } 
24        cout << 2*(pow(2,2*n + 1) - 1) - z << "\n"; 
25    } 
26 
27    return 0; 
28}

This solves the problem!

Before wrapping up our discussion on simulation, let’s solve one last problem.

Exercise 0.1.5: 2016 USACO Third Bronze Problem 2

(Problem Statement)

A farmer has a circular barn with \(n\) rooms numbered \(1\) through \(n\) clockwise. Each room is connected with internal doors with the adjacent rooms and have a door to enter the room from the outside. The farmer wishes to place \(r_i\) cows in the \(i^\text {th}\) room and the farmer will open a single door to a room where cows will enter the room and find their places in clockwise and in organized manner. If the farmer opened a door such that the collective number of distance that all cows moved, i.e. the number of moves between the rooms, is minimum, then what is that minimum distance?

Solution.

After understanding the problem, we can simulate the process where the farmer opened the first room. Then, the total distance can be represented as \((n-1) r_n + (n-2) r_{n-1} + \cdots + 2 r_3 + r_2\) since all cows must move to certain location somehow.

First, we can store the inputs in a vector.

Code 0.1.6: CS0202.26057-03

1int n; 
2cin >> n; 
3vector<int> config(n); 
4for (int i = 0; i < n; i++) { 
5    cin >> config[i]; 
6}

Now we want to simulate the process of cows entering the room and finding the spot. Moreover, we want to simulate all possible cases to actually find the maximum value.

1vector<int> SUM(n); 
2for (int i = 0; i < n; i++) { 
3    SUM[i] = 0; 
4    for (int j = 1; j < n; j++) { 
5        if (j + i < n) { 
6            SUM[i] += j * config[j+i]; 
7        } else { 
8            SUM[i] += j * config[j+i-n]; 
9        } 
10    } 
11}

Lastly, we can complete our solution by printing the minimum value from our SUM vector.

1vector<int> SUM(n); 
2for (int i = 0; i < n; i++) { 
3    SUM[i] = 0; 
4    for (int j = 1; j < n; j++) { 
5        if (j + i < n) { 
6            SUM[i] += j * config[j+i]; 
7        } else { 
8            SUM[i] += j * config[j+i-n]; 
9        } 
10    } 
11}

As you can see, the nested for loops will go through each case where i represents the door that the farmer opens. Then, with the nested for loop, we add the count using the math formula shown above to compute the total distance moved by the cow. With the distances stored, we can now find the minimum value.

1int min = SUM[0]; 
2for (int i = 0; i < n; i++) { 
3    if (min >= SUM[i]) { 
4        min = SUM[i]; 
5    } 
6} 
7cout << min << "\n";

This solves the problem!

Continuing, let’s discuss complete search, or brute forcing all cases.