Notation
It is not hard to observe that since for each village there is a unique way down the river from the village to Bytetown, we can treat the rivers and villages as a tree with the root in Bytetown. Nodes of the tree correspond to the villages (for convenience we will refer to Bytetown as a village too), and node
is the parent of node
when
is the first village downriver from
.
Let
denote the root of the tree, i.e.
corresponds to Bytetown. By
we will denote the number of edges on a unique path from
to
. Clearly, the values of
can be computed for all villages
in linear time. The number of children of node
will be denoted by
, and the number of trees cut near village
will be denoted by
.
Dynamic Programming
We can apply dynamic programming to solve the task. Let
denote the minimal cost of transportation of the trees cut in the subtree rooted in
, assuming that
additional sawmills can be built in the subtree, and the trees not processed in
can be processed in the village of depth
(on the way from
to Bytetown). We compute values of
for each village
, and such numbers
, that
and
. Clearly, when the tree rooted in
has at most
nodes, then
, as we can simply place a sawmill in every village. We can use the following formula:

where
is the cost of transportation when there is no sawmill in
, and
is the cost of transportation when there is one. These costs depend on the distribution of sawmills between subtrees rooted in children of
. Let
and let
be the children of
. Then:


Dynamic Programming One More Time
Let us have a closer look at the recurrences (2) and (3). We do not need to consider every partition of
into a sum of
terms, to compute the values of
and
. It would be time-consuming in case of trees containing vertices with many children. Once again, we can use dynamic programming. Let
denote the cost of transporting the trees cut in subtrees rooted in
provided that
additional sawmills can be built in these subtrees and the trees not processed in these subtrees are processed in a village of depth
. We can make use of the following recurrence:

We define
analogously, but this time we assume that the trees not processed in the subtrees are processed in
. Then

Obviously,
and
. In order to compute all values of
(respectively
), for some
, we compute
(respectively
) for each
and
. It follows that for each pair
it takes
time to compute values
and
, giving total time:

since
is equal to the number of edges in the tree, i.e.
. After computing all values of
the program returns
as the final answer.
Too Much Dynamic Programming
Using dynamic programming twice would not be required if all the vertices in the tree had a small number of children. Fortunately, we can easily construct a binary tree of villages that has the same minimal cost of transportation as the original one. In order to do this, we connect the first child of each vertex to the parent as its left child, create an additional village and connect it as a right child to the parent. Then we connect the other children of the parent vertex in the original tree one by one, each time connecting a child as a left child of the additional village created during connecting the previous child, creating a new additional village and connecting it as a right child of the previous one. Additional villages produce no wood and rivers connecting them to parents are of length
, so they do not affect the total cost of transportation. Building sawmills in additional villages does not lower the minimal cost of transportation, because every sawmill built in an additional village can be moved to the next non-additional village on the way to Bytetown without raising (and even possibly lowering) the total cost.
There are
partitions of
into a sum of
non-negative terms. For each pair
we can therefore compute
for all
in
time. There are twice as many vertices in the binary tree as in the original one. The total computation time is:

One River
It is worth noting, that in the special case, where instead of a tree of rivers there is just one river with multiple villages, the problem is significantly simplified and can be solved more efficiently. In such a case we can use simple dynamic programming. Let us number the villages from
to
upstream. For each village
, and for each number of sawmills
let us denote by
the optimal cost of locating
sawmills in the part of the river downstream from
. The value of
can be computed in
time: we check all
possibilities of placing the upstream-most sawmill using stored values of
. Such an algorithm works in
time.
A special case of such a problem — for just two sawmills — appeared at CEOI 2004, but the upper bound on
was much bigger:
. This required at least an
algorithm, which did not use dynamic programming, but was based on the divide and conquer technique instead. There exists also a solution running in linear time, iterating over all possible locations of the uppermost sawmill and finding the optimal location of the other sawmill in amortized constant time.
Comments