USACO 2019 US Open · Bronze · all three problems
Problem 1 — Bucket Brigade
Subtask structure
Single test, no subtasks — full credit on a fixed 10×10 grid.
Statement
A 10×10 grid contains one barn 'B', one lake 'L', some impassable rocks 'R', and empty cells '.'. Cows stand on empty cells and pass buckets to 4-adjacent neighbours. Find the minimum number of cows needed so that a connected chain links the lake to the barn (the lake-adjacent cow and barn-adjacent cow are each counted; the lake and barn cells themselves are not cows).
Constraints
- Grid is fixed 10×10.
- Exactly one 'B', exactly one 'L', some 'R', rest '.'.
- The lake and barn are not adjacent.
- Time limit: 2s.
Key idea
Plain BFS on a 4-connected grid from L (or its neighbours) to B, treating '.' and the endpoints as passable and 'R' as blocked. The answer is shortest-path-length minus 1 (don't count the endpoint cells themselves). On 100 cells it's instant.
Complexity target
O(100) BFS — trivial.
Reference solution (C++)
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<string> g(10);
for (auto& r : g) cin >> r;
int sx = -1, sy = -1, tx = -1, ty = -1;
for (int i = 0; i < 10; ++i)
for (int j = 0; j < 10; ++j) {
if (g[i][j] == 'L') sx = i, sy = j;
if (g[i][j] == 'B') tx = i, ty = j;
}
// BFS from L; passable cells are '.', 'L', 'B'. 'R' is blocked.
vector<vector<int>> dist(10, vector<int>(10, -1));
queue<pair<int,int>> q;
dist[sx][sy] = 0; q.push({sx, sy});
int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1};
while (!q.empty()) {
auto [x, y] = q.front(); q.pop();
for (int k = 0; k < 4; ++k) {
int nx = x + dx[k], ny = y + dy[k];
if (nx < 0 || nx >= 10 || ny < 0 || ny >= 10) continue;
if (g[nx][ny] == 'R') continue;
if (dist[nx][ny] != -1) continue;
dist[nx][ny] = dist[x][y] + 1;
q.push({nx, ny});
}
}
// # cows = path-length - 1 (exclude L and B themselves, but include neighbours).
cout << dist[tx][ty] - 1 << "\n";
}
Pitfalls
- Don't count L and B as cows. The two endpoint cells are landmarks, not cow positions — answer is BFS distance minus 1.
- Rocks block, not cells with cows. 'R' is the only impassable symbol.
- 4-connectivity only. No diagonal hops.
- Input is the entire 10×10 block. Read line by line, don't pre-allocate the wrong dimensions.
Problem 2 — Milk Factory
Subtask structure
No partial-credit subtasks — single full-credit test set with N ≤ 100.
Statement
A factory has N stations and N−1 directed conveyor belts ai → bi. The underlying undirected graph is a tree. Find the smallest station id that every other station can reach by following directed belts (i.e. the unique "sink" reachable from all sources). If no such station exists, print −1.
Constraints
- 1 ≤ N ≤ 100.
- 1 ≤ ai, bi ≤ N, ai ≠ bi.
- The N−1 edges form a tree when undirected.
- Time limit: 2s.
Key idea
N ≤ 100 — brute force. For every candidate station v, do a directed DFS on the reverse graph from v; if it visits all N stations, then every station can reach v. Return the smallest such v.
Complexity target
O(N · (N + edges)) = O(N²) ≈ 104 ops. Trivial.
Reference solution (C++)
#include <bits/stdc++.h>
using namespace std;
int N;
vector<vector<int>> radj; // reverse adjacency
vector<char> vis;
void dfs(int u) {
vis[u] = 1;
for (int v : radj[u]) if (!vis[v]) dfs(v);
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cin >> N;
radj.assign(N + 1, {});
for (int i = 0; i < N - 1; ++i) {
int a, b; cin >> a >> b;
radj[b].push_back(a); // reverse edge: from b we can walk back to a
}
for (int v = 1; v <= N; ++v) {
vis.assign(N + 1, 0);
dfs(v);
int cnt = 0;
for (int i = 1; i <= N; ++i) if (vis[i]) ++cnt;
if (cnt == N) { cout << v << "\n"; return 0; }
}
cout << -1 << "\n";
}
Pitfalls
- Direction matters. The edges are directed; "all can reach v" is reverse-reachability from v.
- Return smallest, not first found. Iterate v from 1 upward and return on the first hit.
- −1 case is real. A tree with two leaves both being sinks has no universal target.
- Don't try to exploit "tree" structure for N=100. Brute force is faster to write and equally correct.
Problem 3 — Cow Evolution
Subtask structure
Single full-credit test set with N ≤ 25.
Statement
There are N sub-populations of cows; each has a set of characteristic strings (e.g. "horns", "spots"). A "proper" evolutionary tree is one where each feature evolves on exactly one edge. Decide whether such a tree exists for the given feature sets. Output "yes" or "no".
Constraints
- 2 ≤ N ≤ 25 sub-populations.
- 0 ≤ K ≤ 25 features per sub-population; total distinct features ≤ ~25.
- Feature strings: lowercase, ≤ 20 chars.
- All N feature sets are distinct.
Key idea
Equivalent reformulation: a proper tree exists iff no two features f₁, f₂ "cross" — i.e. the four combinations (both, only f₁, only f₂, neither) cannot all appear across the N sub-populations. So enumerate every pair (f₁, f₂) of distinct features and check whether all four bit-patterns 00/01/10/11 occur as restrictions of the input sets to {f₁, f₂}. If any pair hits all four, print "no"; otherwise "yes".
Complexity target
O(F² · N) where F is the number of distinct features. F, N ≤ 25 — trivial.
Reference solution (C++)
#include <bits/stdc++.h>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int N; cin >> N;
map<string, int> id; // feature -> bit index
vector<int> mask(N, 0); // bitmask of features per population
for (int i = 0; i < N; ++i) {
int K; cin >> K;
for (int j = 0; j < K; ++j) {
string s; cin >> s;
if (!id.count(s)) { int n = id.size(); id[s] = n; }
mask[i] |= 1 << id[s];
}
}
int F = id.size();
// Pair check: for every (a,b), do all 4 patterns appear?
for (int a = 0; a < F; ++a)
for (int b = a + 1; b < F; ++b) {
int seen = 0;
for (int i = 0; i < N; ++i) {
int pa = (mask[i] >> a) & 1, pb = (mask[i] >> b) & 1;
seen |= 1 << (pa * 2 + pb);
}
if (seen == 15) { cout << "no\n"; return 0; }
}
cout << "yes\n";
}
Pitfalls
- The right invariant. "Each feature evolves once" ⇔ feature sets form a laminar family ⇔ no two features show all 4 cross-patterns.
- You don't need to build the tree. Just check the local pair condition — sufficient and necessary.
- Map features to bit indices. Strings are clumsy; integer bitmasks turn the check into two shifts.
- Empty feature sets are allowed (K=0). They contribute the "neither" pattern to every pair — harmless on their own.
What Bronze 2019 US Open was actually testing
- P1 — BFS on a tiny grid. The only thing to get right is the off-by-one in "don't count endpoints".
- P2 — reverse reachability on a directed graph. N is small enough that brute-force-from-every-node beats anything fancy.
- P3 — laminar / four-gametes condition. Knowing the "all 4 patterns ⇒ no tree" reformulation is the whole problem.