美国USACO计算机竞赛2019年试题解析
标签:
usaco美国奥林匹克计算机竞ap计算机 |
2019年B1
A fire has broken out on the farm, and the cows are rushing to try and put it out!
The farm is described by
a
..........
..........
..........
..B.......
..........
.....R....
..........
..........
.....L....
..........
The character 'B' represents the barn, which has just caught on fire. The 'L' character represents a lake, and 'R' represents the location of a large rock.
The cows want to form a "bucket brigade" by placing themselves along a path between the lake and the barn so that they can pass buckets of water along the path to help extinguish the fire. A bucket can move between cows if they are immediately adjacent in the north, south, east, or west directions. The same is true for a cow next to the lake --- the cow can only extract a bucket of water from the lake if she is immediately adjacent to the lake. Similarly, a cow can only throw a bucket of water on the barn if she is immediately adjacent to the barn.
Please help determine the minimum number of '.' squares that should be occupied by cows to form a successful bucket brigade.
A cow cannot be placed on the square containing the large rock, and the barn and lake are guaranteed not to be immediately adjacent to each-other.
INPUT FORMAT (file buckets.in):
The input file contains 10 rows each with 10 characters, describing the layout of the farm.
OUTPUT FORMAT (file buckets.out):
Output a single integer giving the minimum number of cows needed to form a viable bucket brigade.
SAMPLE INPUT:
..........
..........
..........
..B.......
..........
.....R....
..........
..........
.....L....
..........
SAMPLE OUTPUT:
7
In this example, here is one possible solution, which involves the optimal number of cows (7):
..........
..........
..........
..B.......
..C.......
..CC.R....
...CCC....
.....C....
.....L....
..........
Problem credits: Brian Dean
The key insight into solving this problem is that the answer can be computed easily using just the locations of the three objects in the scene.
To simplify
things, imagine there is no rock. In this case, the answer is just
the difference in
If we add the rock back to the picture, this actually rarely affects the answer, since we can always route around the rock unless the rock is in the same vertical or horizontal line as the barn and lake and lies between the two, in which case our path takes two additional steps to route around the rock.
My C++ code for solving the problem is below. It should be straightforward to translate to other languages.
#include
#include
#include
using namespace std;
int barn_i, barn_j, rock_i, rock_j, lake_i, lake_j;
int main(void)
{
ifstream fin ("buckets.in");
for (int i=0; i<10; i++) {
string s;
fin >> s;
for (int j=0; j<10; j++) {
if (s[j] == 'B') { barn_i = i; barn_j = j; }
if (s[j] == 'R') { rock_i = i; rock_j = j; }
if (s[j] == 'L') { lake_i = i; lake_j = j; }
}
}
ofstream fout ("buckets.out");
int dist_br = abs(barn_i - rock_i) + abs(barn_j - rock_j);
int dist_bl = abs(barn_i - lake_i) + abs(barn_j - lake_j);
int dist_rl = abs(rock_i - lake_i) + abs(rock_j - lake_j);
// Check for special case where rock is between barn and lake
if ((barn_i==lake_i || barn_j==lake_j) && dist_bl == dist_br + dist_rl)
fout << dist_bl + 1 << "\n";
else
fout << dist_bl - 1 << "\n";
return 0;
}
2019年B2
The milk
business is booming! Farmer John's milk processing factory consists
of
To try and improve efficiency, Farmer John installs a conveyor belt in each of its walkways. Unfortunately, he realizes too late that each conveyor belt only moves one way, so now travel along each walkway is only possible in a single direction! Now, it is no longer the case that one can travel from any station to any other station.
However, Farmer John thinks
that all may not be lost, so long as there is at least one
station
INPUT FORMAT (file factory.in):
The first line contains an
integer
OUTPUT FORMAT (file factory.out):
If there exists a
station
SAMPLE INPUT:
3
1 2
3 2
SAMPLE OUTPUT:
2
Problem credits: Dhruv Rohatgi
2.
If
My code for solving this problem is below.
#include
#include
using namespace std;
int N, incoming[101], outgoing[101];
int main(void)
{
ifstream fin ("factory.in");
fin >> N;
for (int i=0; i
int a, b;
fin >> a >> b;
outgoing[a]++;
incoming[b]++;
}
ofstream fout ("factory.out");
int answer = -1;
for (int i=1; i<=N; i++) {
if (outgoing[i]==0 && answer != -1 ) { answer = -1; break; } // found two sinks -- bad!
if (outgoing[i]==0) answer = i; // found first sink; remember it
}
fout << answer << "\n";
return 0;
}
2019年B3
It is the year 3019, and a surprising amount of bovine evolution has transpired in the past thousand years, resulting in cows with all sorts of interesting features.
The bovine evolutionary record can be described as a tree, starting with a basic ancestral cow at the root with no special features. At each descendant level in the tree, either all cows evolve a new feature (such as fire breathing, below, where all cows with spots ended up breathing fire), or there is a divergent split in the bovine population where some of the cows evolve a new feature (e.g., flying) and some do not.
The leaves at the bottom of the tree indicate all the resulting sub-populations of cows in the year 3019. No leaves (sub-populations) contain identical sets of features. For example, sub-population #1 contains cows with no special features, while sub-population #3 contains telepathic flying cows. Sub-population #2, by contrast, has flying cows that are not telepathic. Sub-population #3 is unique in its combination of flying and telepathic cows.
An evolutionary tree like the one above is called "proper" if each newly evolved feature originates in exactly one edge of the tree (e.g., it evolved into being at a single point in history). For example, a tree would not be proper if spots evolved into being in two separate branches. Given a description of the sub-populations of cows in the year 3019, please determine if these can be described by a proper evolutionary tree.
INPUT FORMAT (file evolution.in):
The first line of input
contains the number of
sub-populations,
OUTPUT FORMAT (file evolution.out):
Please output "yes" if it is possible to form a proper evolutionary tree explaining the origin of these sub-populations, and "no" otherwise.
SAMPLE INPUT:
4
2 spots firebreathing
0
1 flying
2 telepathic flying
SAMPLE OUTPUT:
yes
This example input corresponds to the proper tree shown in the diagram above.
Problem credits: Brian Dean
his is probably the hardest bronze problem we've asked all season, befitting the fact that it's on the US Open contest (for which there is a longer time limit). It takes a good bit of thought to figure out the right solution structure, after which coding isn't too bad. I'll go through a couple of solution ideas in detail below. Hopefully you found this and the other bronze problems fun and challenging this season!
First, it may help to think of an instance where we cannot form a proper evolutionary tree. This would be an instance such that no matter how we form the tree, it would be inevitable that some characteristic would evolve in two distinct places in the tree. It turns out that the minimal such bad example looks like this:
population1: A
population2: B
population3: A B
In other words, we have a population with just trait A, a population with just trait B, and a population with both. If we want to build a tree out of this input, we would need to split on either A or B at the root, but then the remaining two subtrees would both need to have an edge that adds the other characteristic. For example, if the root split into "A" and "not A" branches, then both branches would need to contain an edge that adds the "B" trait.
It will help to actually look at things from the viewpoint of the characteristics instead of from the viewpoint of the populations, so let's "transpose" the input above:
A: population1 population3
B: population2 population3
The fundamental problem here is that there are populations in A only, populations in B only, and populations in both A and B. If we look at the Venn diagram for the sets A and B, the picture therefore looks like this:
Let's call this situation a "crossing" pair of sets. In general, two sets can be disjoint (no overlap), nesting (one inside the other), or crossing (overlap but not nesting). If any two of the characteristics A and B in our instance represent crossing sets as above, then we cannot build a proper tree. On the other hand, if all the characteristics represent sets that don't cross (they are either disjoint or nested), then we get a Venn diagram like this:
If you look at this picture carefully, hopefully you see a tree formed by the nesting structure of the sets:
A tree like this is easy to convert into a proper evolutionary tree. E.g., if we have three children A, B, and C, we could just make three sequential two-way splits that add the A, B and C characteristics.
So, at the end of the day, we actually don't need to build a proper evolutionary tree, but we just need to test of any of our characteristics represent crossing sets; if so (and only if so), a proper tree is impossible to build. This leads to probably the easiest solution of the problem, shown in my code below where I build all the sets of populations having each characteristic and then just test if any pair of these sets is crossing.
Below this code, I'll discuss an alternate solution that also solves the problem and also builds the tree (if possible).
#include
#include
#include
using namespace std;
int N;
vector characteristics[25];
vector all_characteristics;
// Do two sets "cross" -- I.e., are there elements in A, B, and A intersect B?
bool crossing(int a, int b)
{
}
int main(void)
{
}
Another solution approach uses slightly different insight: suppose we have two traits A and B as follows:
A: (4 populations having trait A)
B: (17 populations having trait B)
This means the "+A" edge in the tree (the edge adding trait A) cannot be an ancestor of the "+B" edge, since otherwise every population with the B trait would also have the A trait, contradicting the observation that the size of set A above is smaller than that of B. In general, this means splits on traits involving large sets of populations happen higher in the tree, and in particular the split at the root has to involve the trait with the largest sized set (the set having the most populations).
A method for building the tree therefore is to split on the largest trait, thereby dividing the populations into two groups, and then continuing to divide these groups the same way, always splitting on the largest available trait. If there is ever a tie for the largest trait (say, between traits A and B), some careful thought will convince you that either A or B would be suitable for the split at the root (this is clear if A and B are disjoint, and if A and B are crossing we will get into trouble later no matter what; A and B cannot be nesting if they have the same size). If we ever end up adding the same trait in two different places in the tree, we know that building a proper tree was not possible.
Here's a cool way to think about the approach above. Suppose we wanted to sort a bunch of 3-digit binary numbers. We could first sort them on their leading digit, giving a block of numbers starting with 0 followed by a block starting with 1:
010
000
011
---
110
100
101
Then within each of these two blocks, we can do the same thing, sorting on the second digit. This makes our numbers sorted on their first two digits:
000
---
011
010
---
100
101
---
110
Finally, sorting within each block on the last digit makes everything sorted.
If we write our different populations like this:
population1
population2
population3
population4
Then each population is expressed as a binary number whose 1s and 0s reflect its traits. Now sorting these binary numbers the same way as above ends up basically running the tree construction approach we just described. We first sort on the leading digit, which separates the populations having trait A (the largest trait that we wanted to split on at the root) from those not having trait A. Then we split those groups on the second largest trait, and so on. So building the tree is much like sorting if we look at it from this perspective.
Note that this problem is directly applicable to real-world problems facing evolutionary biologists in terms of figuring out the most likely way organisms evolved in the past. The tree structure we are building is often called a "phylogenetic" tree in this area of study.

加载中…