# Math 560辅导、辅导Python，c/c++程序

- 首页 >> Algorithm 算法
Math 560 Homework 7 Fall 2020
Due: Tuesday, November 3
1. Ski Optimization!1
You have been hired as a consultant at the famed Forty-Two Black Diamonds Ski
Resort. They will let you ski all winter for free in exchange for helping their ski rental
shop with an algorithm to assign skis to skiers.
Ideally, each skier should obtain a pair of skis whose height matches his or her own
height exactly. Unfortunately, this is generally not possible. We define the disparity
between a skier and his or her skis to be the absolute value of the different between the
height of the skier and the pair of skis. Your objective is to find an assignment
of skis to skiers that minimizes the sum of the disparities between all of the
skiers and their skis.
The input to this problem is an array of n skiers (represented just by their heights)
and an array of m ≥ n pairs of skis (each ski pair is represented as just the height of
the skis). These arrays are given in sorted order from shortest to tallest. For example,
we might have (in inches):
skiers = [61 67 73]
skis = [58 62 66 68 72]
(a) [1pt] The infamous Prof. I.M. Rong from the Pasadena Institute of Technology
is trying to steal your job. He proposes the following simple and fast ‘greedy’
algorithm for the problem:
‘The skiers and skis are already sorted from shortest to tallest. So, consider the
skiers one-by-one from shortest to tallest. For each skier under consideration, assign
that skier the pair of skis that most closely match that skier’s height. Then
remove that skier and pair of skis from consideration and repeat the process.’
Find a small example where Prof. I.M. Rong’s algorithm gives a solution that
is worse than the optimal solution. You will need to provide a particular small
set of skier heights, a small set of ski heights, show the solution that Prof. I.M.
Rong’s algorithm would produce, and then show a solution that is better.
ANSWER: Consider the set:
skiers = [60 65]
skis = [55 61]
According to Prof. I.M. Rong’s algorithm, we would first consider the skier of
height 60 and assign the skis of height 61. This leave the skis of height 55 for the
1Adapted from problem sets created by Harvey Mudd College CS Professor Ran Libeskind-Hadas.
1
skier of height 65. This solution has a disparity of 1 + 10 = 11. It is clearly better
in this case to give the height 55 skis to the height 60 skier, and the height 61
skis to the height 65 skier, for a disparity of 5 + 4 = 9.
(b) [1pt] Often, we need to infer (and prove) a mathematical fact about our problem
that we can exploit in developing our algorithm. Another consultant, Prof. Sue
Persmart, made the following conjecture: If we have a short person and a tall
person, it is never better to give the shorter person a taller pair of skis than were
given to the tall person (we will call this an inversion). Your task is to prove this
conjecture!
Specifically: Let x and y be the heights of two skiers with x < y and let sx and
sy be the heights of the skis with sx > sy. We’d like to show that if the person
with height x is given the skies with height sx and the person with height y is
given the skies with height sy, then switching the skis between these two skiers
would not increase the disparity (i.e., removing the inversion does not make the
solution any worse).
One way to do this is to break the analysis up into a number of cases such as the
case x < y < sy < sx, or the case x < sy < sx < y, etc. If you choose to use this
approach, list the cases that you would need to consider and then analyze just
one of these cases. (This is intended to save you time, because we trust that if
you can do one case, you could do them all!)
ANSWER: There are six cases to consider:
x < sy < sx < y
x < sy < y < sx
x < y < sy < sx
sy < x < sx < y
sy < sx < x < y
sy < x < y < sx
Let’s consider the case where x < y < sy < sx. In this case, when x is given sx
and y is given sy, the disparity is
|sx − x| + |sy − y|.
If the skis were switched, then the disparity would be
|sx − y| + |sy − x|.
Now, since x < y < sy < sx, we know that all four quantities sx −x, sy −y, sx −y,
and sy − x are positive. Therefore, both of the above disparities simplify to
|sx − x| + |sy − y| = sx + sy − x − y = |sx − y| + |sy − x|.
2
Therefore swapping the skis did not increase the disparity.
We can do this for all six cases, and so we can conclude that removing an inversion
never leads to a worse solution. This tells us that there is an optimal solution that
does not have an inversion. If we have an optimal solution that has inversions,
we can remove those inversions without making the solution worse, and would
therefore still have an optimal solution (but without inversions).
(c) [1pt] Assume that there are n skiers and n pairs of skis. Describe (in English)
a fast algorithm for assigning skis to skiers, briefly explain how the proof of correctness
would work (using the result from part (b)), and give the running time
of your algorithm.
For part (d), you may assume that you have a function that correctly implements
this algorithm and optimally assigns the n skis to the n skiers, returning the optimal
disparity:
partC(skiers[0:n], skis[0:n])
ANSWER: From part (b), we concluded that we can always find an optimal solution
without inversions. Note that when there are the same number of skis and
skiers, there is only one solution without inversions: assign the smallest skis to
the smallest skier, the second smallest skis to the second smallest skier, etc. This
will take O(n) time.
Note: we could also have assigned the largest ski to the largest skier, etc. This
would have given the same assignment since there are equal numbers of skis and
skiers.
3
(d) Finally, consider the general case that m ≥ n.
i. [3pts] In simple and clear pseudo-code or English, describe a recursive algorithm
for solving this problem. For now, assume that ‘solving’ means just
returning the number which is the sum of the disparities in an optimal solution.
Make sure to describe the base cases and the recursive call(s).
ANSWER: In my recursive function, I will consider the smallest ski and the
smallest skier. I will then decide whether to assign that ski to that skier
(use-it), or skip that pair of skis (lose-it). Note that we cannot skip a skier.
def assignSkis(skiers, skis, i, j):
# Returns the minimum disparity when
# assigning skiers[i:n] and skis[j:m].
# Note: n = len(skiers) and m = len(skis).
n = len(skiers)
m = len(skis)
# No more skiers who need skis, so 0 more disparity.
if i = n:
return 0
# Same number of skis and skiers remaining, return from part (c).
elif n-i == m-j:
partC(skiers[i:n], skis[j:m])
# Go to use-it or lose-it strategy.
else:
# Use-it: assign the shortest skis to the shortest skier and
# see what happens.
# Note that we have to add the disparity from this match.
useIt = |skiers[i]-skis[j]| + assignSkis(skiers, skis, i+1, j+1)
# Lose-it: don’t assign the shortest skis to the shortest skier.
# Note that it is never better to assign these skis to a taller
# skier since that would result in an inversion.
# So this case is: don’t use the shortest skis at all.
loseIt = assignSkis(skiers, skis, i, j+1)
# Return whichever case gave the smallest disparity.
return min(useIt, loseIt)
4
ii. [2pts] Next, describe how you would implement this algorithm using dynamic
programming. In particular, describe what the DP table looks like and the
order in which the cells would be filled in. A picture may help (although the
picture alone will not be graded). For those of you interested in practical
implementation, it may be informative to write the actual DP pseudo-code
for filling the table.
Note: there are dozens of ways to setup this table. I chose this method because
I like having the solution live in the bottom right corner.
ANSWER: Put skis across the top and skiers down the side (in reverse
order, since we are removing from the front rather than from the
back - so i + 1 is up and j + 1 is left).
Also, remember that the remaining skiers are [i:n] and the remaining skis
are [j:m].
• Everything below the main diagonal from the upper-left corner does not
have to be considered, because those correspond to cases where there are
more skiers than skis remaining, which is not allowed.
• The top row is a base case where there are no skiers, so fill it with 0.
• The main diagonal from the upper-left corner is a base case where there
are the same number of skiers and skis remaining. So this diagonal can
be filled using partC(skiers[0:n], skis[0:n]), which doesn’t require
any recursive calls. It will, however, require k work for the kth element
in this diagonal (assigning k skis to k skiers and summing the k different
disparities).
• For any given square in our table, we will either need the value directly
left (the lose-it case with one fewer set of skis, since j + 1 is left) or the
value diagonal to the upper-left (the use-it case with one fewer set of skis
and one fewer skiers, since i + 1 is up and j + 1 is left).
• We have the top row and the main diagonal filled from base cases, so we
can now fill in the table one row at a time, left-to-right, starting with
second row.
• We could also fill in the table one column at a time, left-to-right, starting
with second column.
• It is slightly better to fill in the table one diagonal at a time, left-to-right.
This way, we can stop when we reach the bottom right element and avoid
an extra n
2/2 elements.
5
My table will look like this:
(continued on next page)
6
iii. [1pt] What is the running time of your algorithm?
ANSWER: We have two parts of the algorithm to count: filling in the base
cases, and filling in the rest of the table.
Note that the base cases along the first row simply take n work to fill in the
n zeros, but the base cases along the diagonal require k work to compute the
kth entry on this diagonal. So the total work for filling in the base cases is:
n + (1 + 2 + · · · + n) ∈ O(n
2
).
Note that this can actually be done faster by using the use-it (no lose-it option
for this diagonal) approach to iteratively fill in the main diagonal, taking
O(n) time instead.
Now consider the work to fill in the rest of the table. If we filled across rows
or down columns, we would have to fill in mn − n
2/2 + n =∈ O(mn) cells,
each taking constant time, for a total of O(mn) time.
If we filled down a diagonal, we would have skipped an extra n
2/2 cells. So
now we would have to fill mn − n
2
cells. Along with the time to fill the main
diagonal (quickly), this gives a total work of mn − n
2 + n. We can now make
one an observation: we have been guaranteed that there are always more skis
than skiers, and so m ≥ n. Therefore mn ≥ n
2
, and so the overall runtime is
O(mn). This is not always a tight bound, because if m = n + c, the runtime
would give
mn − n
2 + n = n
2 + cn − n
2 + n = (c + 1)n ∈ O(n).
Very technically, the tight bound we should report is:
O(mn − n
2
).
This trick will not work if we filled by rows or columns, because the runtime
was mn − n
2/2 + n, and so the n
2
terms wont actually cancel.
iv. [1pt] Briefly, describe how you could reconstruct an actual optimal solution
matching skiers with skis using your DP table.
ANSWER:
• If the value in a given cell is the same as the value in the cell immediately
to its left, then we were in the lose-it case. Else, the use-it case.
• If we were in the lose-it case, then the skis for that column were not used
at all. Skip those skis and move on to the cell directly to the left.
• If we were in the use-it case, then the skis for that column were assigned
to the skier from that row. Assign those skis to that skier, and move on
to the cell diagonally to the upper-left.
7