Title: Advice on BIO Problems
1Advice on BIO Problems
- Especially questions 2 and 3
By John Mellor
2The British Informatics Olympiad
- Annual computer programming competition
- 3 hour exam
- Top 15 competitors attend final in Cambridge
- 4 selected for international team
3Question 1
- Question 1s vary a lot, but it is generally
fairly simple to see a solution. There are some
basics you need to know though - parsing input
- converting between datatypes
- string manipulation
- output
4Question 2s
- Very variable
- Implementation problem
- PLAN!
- List data you are given, must store, and must
output. - List operations you must perform on the data
- Use these to form plan of functions
- (with some code to control them)
- Break operations into pieces andwrite them!
5Important Things For Question 2s
- Ideally you should know how to create use
- Multi-dimensional arrays
- Arrays of dynamic length (aka ArrayLists or
Vectors) - Objects
- Hashtables (aka Maps)
- Sorting arrays etc.
6Question 3s
- Shorter than solutions to question 2
- Require more thought
- Plan thoroughly!
- Questions are arguably more predictable
7Recursive Algorithms
- When problem has trivial basic case
- Recursive algorithms solve a problem by
repeatedly reducing it to a problem one step
closer to the basic case
if (trivial case) solve directly else solve in
terms of a slightly easier case
8Recursion Example Factorials
- Lets look at how you could find n!. It is
defined as - n! 1 x 2 x ... x (n-2) x (n-1) x n
- (Note that you could solve this particular
problem just by using a loop, but in more complex
cases loops might be unmanageable)
function factorial(int n) if (n 1 n
0) return 1 return n factorial(n-1)
9Dynamic Programming(aka Doing things the easy
way)
- When using recursion you do need to watch out
that you dont repeatedly solve the same problem.
For example, the following recursive algorithm
will find the nth Fibonacci number - But it is very slow for large values of n
function fib(int n) if (n1 n2) return
1 return fib(n-1) fib (n-2)
10Fibonacci example part 2
- because it works all the intermediate steps
between fib(n) and fib(1) many times over
and fib(2) is defined in terms of fib(1) and
fib(0)
11Start small
- The best way to solve this would be to start by
working out smaller Fibonacci numbers and working
upwards
function fib(int n) int terms new
intn1 terms0 1 terms1 1 for (int
i2 iltn i) termsi termsi-2termsi-1
return termsn
This way each number would only be found once
12An easier way to start small
- It is often easier to just write the first
recursive function you can think of than to work
out what the most efficient way of tackling a
problem would be. - So cheat!
- Store results in an array and reuse them next
time.
13Recursive Fibonacci with Cheat
- Heres an example I took the existing
recursive Fibonacci function, and added the red
code to it
int done //I assume this has been initialised
and defaults to 0 function fib(int n) if
(donen ! 0) return donen if (n0 n1)
return 1 donen fib(n-1) fib
(n-2) return donen
14Useful data-structures to cheat with
- Look at the argument(s) to your function
- Integers can be used as indexes in an array
- Anything else can be used as a key for a
Hashtable (aka Map).
15Fibonacci Cheat with a Hashtable
- Just as an example
- (note that String.valueOf(n) is just an example
(in Java) of how to turn n an integer into an
object, and isnt even a particularly good way.
Replace it with a customised conversion)
Hashtable done new Hashtable() function
fib(int n) if (done.containsKey(
String.valueOf(n) )) return done.get(String.valueO
f(n)) if (n0 n1) return 1 done.put(
String.valueOf(n), fib(n-1) fib (n-2)
) return done.get( String.valueOf(n) )
16Another Dynamic Programming Example
- Suppose you need to calculate the highest
possible sum of numbers passed on a route from
the top to the bottom of this triangle, with
every step diagonally down - 7
- 3 8
- 8 1 0
- 2 7 4 4
- 4 5 2 6 5
17Another Dynamic Programming Example (part 2)
- The obvious, but slow, way is to write a
recursive function which gives the answer in
terms of the highest sum path of the two sub
triangles starting diagonally down to the left
and right of it.
function highestSum(int row, int col) if (row
num_rows-1) return trianglerowcol int
left highestSum(row1, col) int right
highestSum(row1, col1) return
trianglerowcol max(left, right)
18Another Dynamic Programming Example (part 3)
- However this computes each sub-triangle many
times. - The clever, and quick, way is to start from the
bottom - 30
- 7
- 23
- 23 21
- 3 8
- 20 13
- 20 13 10
- 8 1 0
- 12 12 10
- 7 12 10 10
- 2 7 4 4
- 5 5 6 6
- 4 5 2 6 5
19Another Dynamic Programming Example (part 4)
- The code would look something like this
function highestSum() for (int rowrows-2
rowgt0 row--) for (int col0 colltrow-1
col) trianglerowcol max(
trianglerow1col, trianglerow1col1
) return triangle00
20Another Dynamic Programming Example (part 5)
- But again we could just use the obvious approach
and cheat to make it as fast
int done //I assume this has been
initialised and all set to -1 function
highestSum(int row, int col) if
(donerowcol ! -1) return donerowcol if
(row num_rows-1) return trianglerowcol in
t left highestSum(row1, col) int right
highestSum(row1, col1) donerowcol
trianglerowcol max(left, right) return
donerowcol
Below is an example of how you would actually use
this function
done new intnum_rowsnum_rows //since same
no. of rows as cols for (int x0 xltnum_rows
x) for (int y0 yltnum_rows y) donexy
-1 int ans highestSum(0, 0)
21Backtracking
- General problem solving tool for finding a state
which satisfies several criteria. - Effectively tries every possibility.
- Analogous to solving a maze. Whenever
backtracking has a choice of path it will choose
one at random and follow that path and all
subpaths until it has exhausted all possibilities
resulting from that pathchoice.
22But its not all about mazes!
- All kinds of computing problems can be solved by
backtracking. -
- Backtracking eliminates partial solutions, so is
faster than it may sound.
23So when do you do it?
- When the solution to the problem
- Can be constructed in a series of steps, with
each step adding a part to the solution. - At every step there will be several ways to
extend the partial solution from the previous
step, some of which will lead to a solution,
while others wont.
24And how do you do it?
- This is where recursive algorithms really come in
handy.
function solve() if (done) return true for
(each new step possible from current position)
make step, storing it in some global data
structure if ( solve() ) return true undo
step, removing it from the data
structure return false //n.b. you could
just pass variables as parameters to the function
instead of storing them in a global data structure
25A slight variation on backtracking
- Sometimes you are required to output the number
of solutions instead. Heres how you could do so
int solutions 0 function solve() if (done)
solutions solutions 1 else for (each new
step possible from current position) make
step, storing it in some global data
structure solve() undo step, removing it
from the data structure)
26For example BIO 2005 q3 - Movies
- A group of actors
- must each film a
- certain number of
- scenes.
- Only one actor is in each scene.
- Each actor must shoot his/her scenes in order.
- Actors vary in seniority and can never have
filmed more scenes than their seniors. - Find the number of
- different orders in
- which the scenes
- could be shot.
int actors int scenes int done function
main() actors inputInteger() scenes new
intactors done new intactors for (int
i0 iltactors i) scenesi
inputInteger() int solutions
solve() print(solutions) function solve()
int solutions 0 for (int i0 iltactors
i) if (scenesi gt 0 (i0 donei lt
donei-1)) scenesi-- donei sol
utions solve() scenesi donei--
for (int i0 iltactors i) if (scenesi
gt 0) return solutions return 1
27And yes, you can cheat here too
int actors int scenes int done Hashtable
done new Hashtable() //note that an eight
dimensional array could have function main()
//been used instead of a Hashtable actors
inputInteger() scenes new intactors done
new intactors for (int i0 iltactors i)
scenesi inputInteger() int solutions
solve() print(solutions) function solve()
if (done.containsKey(getKey())) return
done.get(getKey()) int solutions 0 for (int
i0 iltactors i) if (scenesi gt 0
(i0 donei lt donei-1)) scenesi--
donei solutions solve() scenesi
donei-- for (int i0 iltactors i)
if (scenesi gt 0) done.put(getKey(),
solutions) return solutions done.put(getKey(
), 1) return 1 function getKey() String key
"" for (int i0 iltactors i) key
donei return key
28Sensible sizes
- You can store a maximum of about 8,000,000
integers or 32,000,000 characters. -
- performing a simple operation a billion times
takes about 5 seconds, so if you have, say, -
- that will use up all your time
for (int x0xlt1000x) for (int
y0ylt1000y) for (int z0zlt1000z) do
something
29Getting help
- Download the manual, your favourite tutorial,
etc. - e.g. try finding out about dynamic length arrays,
Hashtables and sorting arrays
30Help! It doesnt work!
- Check your program against the sample run, and
preferably more - Error messages are hopefully self-explanatory.
- If its wrong or times out
31Finding Mistakes
- Re-read question!
- Check code (especially 1 errors)
- Use the debugger
32About marking
- Correct solutions more important than speed.
- Watch out for the simplest cases
- Could hardcode example and the simplest cases for
questions you couldnt do - Written questions often possible anyway
33Thanks for listening
- Downloads etc. at
- jomel.me.uk/programming/bio