Explanation
Each fence can be thought of as two grid units. The reason we use two is for cases such as . If we only use one grid unit per fence, there would be no area inside it, and thus we would undercount.
We can model the fences, and floodfill to find the number of connected components. The region not enclosed by a fence is also counted as one connected component. By merging the regions enclosed by a fence with the region not enclosed by the fence, by means of a gate, we can ensure the farm is connected. The cows are able to go from a region enclosed by a fence into the region not enclosed by a fence and subsequently visit another region which is enclosed by a fence.
Therefore, the number of gates that must be used is equal to the number of regions enclosed by the fence, which is the number of connected components minus one.
We can perform floodfill and have the fences signify a stopping point. If a fence is seen, we no longer continue to floodfill in that direction. This is because floodfill is performed to simulate the cows' movement, and a cow cannot walk through a fence.
To count the number of connected components, we perform floodfill from every point in our boundaries (more on that in the warning below). If we have already visited a point, we don't floodfill any further. If we have to start a new floodfill, it means the point we're starting on was not reached from prior floodfills, meaning it is in a separate component. Thus, we add one to our count of connected components.
Warning!
The official solution stores the farm in a boolean array with the origin at , but this is not sufficient. Since each fence segment is doubled, the maximum distance in each direction could be units, causing an input such as s to go out of bounds.
To not go out of bounds, an array of size should be used: unit for the origin position, units in each direction from the origin and more unit in each direction to ensure that the farm includes area beyond the fence. The origin is at , and there is "buffer" space at row/column and , which is obtained from adding or subtracting from the origin then correspondingly adding or subtracting .
If we floodfill through the entire grid without constraints,
a stack overflow would occur. This is why we must use maxx, minx, maxy, and miny.
Implementation
Time Complexity:
C++
#include <cstdio>#include <iostream>#include <map>using namespace std;void ff(int i, int j);bool fence[4003][4003] = {false};bool visited[4003][4003] = {false};int maxx = 2001, minx = 2001, maxy = 2001, miny = 2001;int main() {
Java
Optimization
Recursive DFS (which the C++ code uses) is too slow, so here we must use an iterative DFS approach.
import java.io.*;import java.util.*;public class BuildGates {private static final Map<Character, int[]> DIR = new HashMap<>() {{put('N', new int[] {-1, 0});put('S', new int[] {1, 0});put('E', new int[] {0, 1});put('W', new int[] {0, -1});
Alternate Faster Solution
It is possible to make the following 2 observations:
- For each contiguous closed region, there must be 1 gate. In a minimum state, each region has exactly 1 gate. For example, if there are 2 regions, there must be 2 gates.
- Each time FJ comes across a node he has visited along an edge he has not crossed in either direction, he creates exactly 1 new region. In other words, FJ creates exactly 1 new contiguous closed region if all of these conditions are met:
- FJ walks along an edge from point to
- He did not walk from to in the past
- He did not walk from to in the past
- is a point he had already visited
Under these observations, we can use a set of visited edges and visited nodes, and keep track of the number of contiguous closed regions. This solution is about 10 times faster than flood filling due to lookup and insertion.
Implementation
Time Complexity:
C++
#include <bits/stdc++.h>using namespace std;int main() {freopen("gates.in", "r", stdin);freopen("gates.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);
Python
with open("gates.in") as read:n = int(read.readline().strip())s = read.readline().strip()visedge = set()visnode = set()prev = (0, 0)visnode.add(prev)ans = 0
Join the USACO Forum!
Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!