Today I finally managed to give out the prizes I have prepared:

Prizes for 0th, 1st and 2nd place.

Prizes for 0th, 1st and 2nd place.

There was one for Rimas, one for dbaltrus, and one for me, as I felt I deserved a price too (in addition to the kind and not-so-kind words of feedback).

I want to thank all who participated once again – I hope you found benefit in it. Also, I want to thank Dr Mary Cryan for her support and for advertising the blog during the lectures.

I wish you happy holidays and good luck on the exam!

Happy Hacking.

– Stan

Challenge 9 (and final) has finished. There were two submissions, with Rimas’s one being slightly more correct than that of dbaltrus. Still, thanks to both for participating. Here’s the updated scoretable:

Place Nickname C1 – C7 score C9 score Total
1 Rimas 79 % 300/300 82 %
2 dbaltrus 63 % 250/300 66 %
3 Andrew 16 % 14 %
4 spooky 15 % 13 %
5 svepe 14 % 12 %

So by this the practice experiment is over. Once again big thanks to all who participated and to all who were following the progress. Also, good luck on the exam when it comes.

Happy Hacking!

– Stan

P.S. There will be prizes for the most dedicated!

Here are my solutions to the last challenge: WinChal9.

It took me about 4 hours to code them just by looking at the challenge specification, while talking to a very communicative friend of mine and watching videos on the Internet. My point is that it would have taken you less, if you tried!

My solution for finding the convex hull is using Graham’s scan and the implementation is also very close to the one in the lecture notes, so nothing fancy here either.

I hope you enjoyed the problems. Await final results soon.

– Stan

Welcome back to uoeadspractice! This is going to be the seventh (two were missing) and last challenge, incorporating the remaining material. The problems will be:

1. Heuristics for Kruskal;
2. Kruskal; and
3. Convex Hull.

1. Heuristics for Kruskal

In order to implement Kruskal’s algorithm, one needs to have an implementation of Disjoint Sets. Thus the first task is to implement this data structure, together with some heuristics which make Kruskal run faster.

Your data structure needs to maintain a collection of disjoint sets and have three public methods (slide 6):

  • makeSet(int x): creates a new set with only member x;
  • union(int x, int y): joins the set containing x with the set containing y; and
  • findSet(int x): returns the set containing x.

The DisjointSet data structure should be implemented as a forest, and the heuristics that need to be included are Union-by-Rank and Path Compression.

Union-by-Rank is attaching the tree of smaller rank to the one of higher tank, when joining two trees. Thus it should be part of the union method.

Path Compression is re-linking nodes during a findSet operation. All the nodes on the path from x to the root of its tree are re-linked as direct children of the root to increase lookup time for later lookups.

2. Kruskal

The algorithm of Kruskal for computing an MST is slightly odder, in my honest opinion. Nevertheless, it is a very beautiful and elegant algorithm and deserves to be implemented! Roughly put, it goes like this:

  1. Start with considering all vertices of the graph as separate connected components;
  2. Sort the edges of the graph by increasing weight;
  3. For each edge: if it is connecting two different connected components then add it to the MST
  4. Done!

It takes longer to convince yourself that Kruskal is correct, but trust me – it is. Better still – read the slides (slide 5).

The complicated part of the implementation is implementing Disjoint Sets, but you already did this in problem 1, so it should be piece of cake now.

Format:

Graph kruskalMST(Graph graph);.

3. Convex Hull

Convex Hull

The problem for finding a convex hull is maybe my favorite one in the course. It is a pity that it was not in the examinable material last year, but maybe you will have better luck and have an exam question on it!

So the problem is as follows: given a cloud of points, find the list of points lying on the convex hull of the cloud.

Format:

C++:

vector<pair<int, int> > convexHull(vector<pair<int, int> > points);

Java:

ArrayList<Point> convexHull(ArrayList<Point> points);

Test range:

You should be able to wrap 106 points in less than a second.

How to Submit

After you’re done, put the functions in one file called winchal9.cpp or WinChal9.java. In case you are using Java, obviously you need a class. Call it WinChal9 and let it reside in a package called uoeadspractice.<nickname>.challenge9. Also, add a comment with your nickname in the beginning of the file.

When you’re done with that, send the file(s), together with a nickname, and optionally degree, year and university (if it is not University of Edinburgh) to uoeadspractice a t gmail d o t com. The deadline for submitting your code is Sunday 18 November 2012 2359 GMT.

Happy Hacking!

-Stan

Challenge 7 has finished. There were two perfect submissions. Here’s the updated scoretable:

Place Nickname C1 score C2 score C3 score C4 score C6 score C7 score Total
1 Rimas 200 / 200 280 / 300 270 / 300 280 / 300 300 / 300 79 %
2 dbaltrus 200 / 200 260 / 300 280 / 300 300 / 300 63 %
3 Andrew 200 / 200 16 %
4 spooky 360 / 400 15 %
5 svepe 260 / 300 14 %

I hope you enjoyed it. Await the next challenge soon.

Welcome to the challenge of week 7. It will be about Minimum Spanning Trees and a real world problem. Here is the list of tasks:

  1. Build a Graph;
  2. Implement Prim’s Algorithm for building an MST;
  3. Counting change.

Minimum Spanning Tree

1. Graph

This problem is roughly the same as the one in C6: design a Graph data structure. It turned out that you do a better job at this than me, so I will not give a skeleton implementation this time. Just bear in mind that your graph should not be directed, and should have weights associated with its edges.

It is important that your implementation is clear, and that method / field naming is helpful for determining the purpose of the corresponding method / field.

2. Prim

The first algorithmic part of challenge 7 is implementing Prim’s algorithm for finding a MST of a graph. It is the first thing that comes to mind when one puts the effort into designing such an algorithm: start from some random vertex and then greedily add the shortest available edges to your tree. You can get a more formal introduction from lecture slides 8-22.

Implement this algorithm, in the following format:

Graph primMST(Graph graph);

As usual it should be reasonably fast, so use a heap for the priority queue.

3. Counting change

Initially, I was planning to make you implement Kruskal, but then there wouldn’t be any space left for a nice practical challenge I have in mind! So Kruskal is postponed for next week and instead you get to solve the following problem that occurs to each of us, every day: in how many ways can you count your pennies. The problem originates from Project Euler problem 31.

Our version, however, would be the following:

Count the number of ways in which you can pay x pence, using an arbitrary amount of 1p, 2p, 5p, 10p, 20p, 50p, 1pound, and 2pound coins. The number x will be less than 105 and you should produce the result faster than I can blink (but have in mind that I can blink quite quickly). Oh, and please don’t precompute the answers 🙂

Here is the format:

long countChange(int x);

Hint: If you’re clueless you can first solve Problem 31 on Project Euler and then read the nice PDF they have there (it becomes available after you solve the challenge). After that it should be a breeze.

How to Submit

After you’re done, put the functions in one file called winchal7.cpp or WinChal7.java. In case you are using Java, obviously you need a class. Call it WinChal7 and let it reside in a package called uoeadspractice.<nickname>.challenge7. Also, add a comment with your nickname in the beginning of the file.

When you’re done with that, send the file(s), together with a nickname, and optionally degree, year and university (if it is not University of Edinburgh) to uoeadspractice a t gmail d o t com. The deadline for submitting your code is Sunday 04 November 2012 2359 GMT.

Happy Hacking!

-Stan

Hi again, folks. Two submissions for this week: dbaltrus’s and Rimas’s. Apart from the design of the DS being slightly confusing for both solutions, the algorithms worked fine.

Updated scoretable:

Place Nickname C1 score C2 score C3 score C4 score C6 score Total
1 Rimas 200 / 200 280 / 300 270 / 300 280 / 300 75 %
2 dbaltrus 200 / 200 260 / 300 280 / 300 56 %
3 Andrew 200 / 200 20 %
4 spooky 360 / 400 18 %
5 svepe 260 / 300 17 %

I hope you enjoyed it. Await the next challenge soon.

I know what you were thinking – “It is high time for a new challenge”. I hear you. Here it is; topic is network flow.

1. Graph

The graph is arguably the most fundamental data structure in all computer science. Today you have the chance to implement one. Here is a pseudo skeleton that you need to fill in:

Java:

// Represents a single vertex of the graph.
public class Vertex {
public Vertex (int id);
public int getId();
}
// Represents a weighted edge connecting two vertices
public class Edge {
public Edge(int weight, Vertex thisV, Vertex other);
// Gets the vertex which is not v
public Vertex getOtherVertex(Vertex v);
public int getWeight();
public Vertex getTarget();
public Vertex getSource();
}
// Represents the whole graph
public class Graph {
public Graph(Vertex [] vertices, ArrayList [] neighbours);
public int getNumberOfVertices();
// Literally, returns any vertex of the graph
public Vertex getAnyVertex();
public ArrayList getEdgesOf(Vertex v);
}

C++:

#include <fstream>
#include <vector>
using namespace std;
// Represents a single vertex of the graph.
class Vertex {
public:
Vertex (int id);
int Id();
}
// Represents a weighted edge connecting two vertices
class Edge {
public:
Edge(int weight, Vertex& thisV, Vertex& other);
// Gets the vertex which is not v
Vertex& GetOtherVertex(Vertex& v);
int Weight();
Vertex& GetTarget();
Vertex& GetSource();
}
// Represents the whole graph
class Graph {
public:
Graph(Vertex vertices[], vector neighbours[]);
int getNumberOfVertices();
// Literally, returns any vertex of the graph
Vertex& getAnyVertex();
vector getEdgesOf(Vertex& v);
}

Note that this graph of yours can be used for directed, weighted graphs, which is how residual networks can be represented. Also, you don’t have to necessarily use one of these two skeletons, but they can be a good starting point. Anything that will help you solve 2 and 3 will do.

2. The Edmons-Karp Heuristic

In order to have a good implementation of Ford-Fulkerson, we need to use the Edmons-Karp heuristic. Thankfully, it is quite a simple thing. Read the notes: ADS Network Flow, page 39. Then code up a method of the format:

Java:

Graph edmonsKarp(Graph residualNetwork);

C++

Graph EdmonsKarp(Graph const& residualNetwork);

[If you wonder, why the const is misplaced, read this.]

For a test network of less than 106 nodes and 107 edges, your algorithm should run in less than 1 second.

3. The Ford-Fulkerson Algorithm

This one finds the maximum flow of a network. You can go and read the description in the lecture notes again, but to be honest, looking at examples will give you understanding what the algorithm is about faster than trying to understand its formal definition. You can find examples on pages 22, 26, and 38. Then implement the algorithm in the following format:

Java:

int fordFulkerson(Graph residualNetwork);

C++:

int FordFulkerson(Graph& residualNetwork);

For a test network of less than 1000 nodes and 104 edges, your algorithm should run in less than 1 second. Oh, and the maximum flow will be less than 1000.

How to Submit

After you’re done, put the functions in one file called winchal6.cpp or WinChal6.java. In case you are using Java, obviously you need a class. Call it WinChal6 and let it reside in a package called uoeadspractice.<nickname>.challenge6. Also, add a comment with your nickname in the beginning of the file.

When you’re done with that, send the file(s), together with a nickname, and optionally degree, year and university (if it is not University of Edinburgh) to uoeadspractice a t gmail d o t com. The deadline for submitting your code is Sunday 28 October 2012 2359 GMT.

I finally graded challenge 4, thanks for the patience. It was a tough competition on this one between the current leader – Rimas – and a newcomer – svepe. They both scored high, with Rimas cheating and scoring 10 points more than svepe 🙂 Good work to both of you.

Updated scoretable (it actually starts to look like one):

Place Nickname C1 score C2 score C3 score C4 score Total
1 Rimas 200 / 200 280 / 300 270 / 300 71 %
2 dbaltrus 200 / 200 260 / 300 47 %
3 Andrew 200 / 200 25 %
4 spooky 360 / 400 23 %
5 svepe 260 / 300 22 %

The next challenge will soon be announced. Expect Dynamic Programming and Minimum Spanning Trees.

– Stan

Hello again and welcome back to uoeadspractice! Before I go on and tell you the problems for this week, I would like to remind you that this is an informal blog and is not directly connected to the ADS course or the University of Edinburgh, although they are inspiration for creating and maintaining it. Even if you missed the previous challenges, you can still participate, be it just for fun. Also, you don’t need to solve everything in order to submit solutions, so just relax and enjoy.

This week’s challenge will be all about sorting again (for the last time, I promise). There is something to be excited about, though – you are supposed to do it in linear time! The tasks are the following:

  1. Counting sort;
  2. Radix sort;
  3. Bucket sort.

1. Counting Sort

It is well known that comparison-based sorting can not be done in time less than O(n * lg n). But what if we remove this restriction? Or better said, if we impose more restrictions on the data, particularly that each element belongs to a set of finite possibilities that has a total order. In the context of whole numbers this would mean that each element of the array that we want to sort belongs to a given interval.

Well, if that is the case, then we can simply count the number of occurrences of each number in that interval, and then use this information to reconstruct the array in sorted state. I can put the details in words, but why not look at a simulation instead? Note that this is not the only way of using the counting array to reconstruct the sorted array. It is you chance to be creative! Specs:

Test range:

The size of the input array will be less than 108.
The elements of the input array will be 8-bit integers.

Your function is expected to execute for less than 1 second.

Format:

C++:

vector<int> CountingSort(vector<int> &A);

Java:

List<Integer> countingSort(List<Integer> A);

2. Radix Sort

RadixSort is another “more-than-just-comparison” sorting algorithm. It was invented during the times when you could literally get a hold of someone’s data:

The idea is the following: sort the array multiple times, using the digits of the elements as keys, starting from the least significant one, and finishing at the most significant one. If you use Counting sort for each of these steps the asymptotic run-time would still be better than that of a comparison-based algorithm.

Example:

Sort [123, 13, 1, 542, 521, 132, 2, 10, 21]:
1: [123, 013, 001, 542, 521, 132, 002, 010, 021] -> [010, 001, 521, 021, 542, 132, 002, 123, 013];
2: [010, 001, 521, 021, 542, 132, 002, 123, 013] -> [001, 002, 010, 013, 521, 021, 123, 132, 542];
3: [001, 002, 010, 013, 521, 021, 123, 132, 542] -> [001, 002, 010, 013, 021, 123, 132, 521, 542];
Result: [1, 2, 10, 13, 21, 123, 132, 521, 542], which really is sorted.

Test range:

The size of the input array will be less than 107.
The elements of the input array will be 32-bit integers.

Your function is expected to execute for less than 1 second.

Format:

C++:

vector<int> RadixSort(vector<int> &A);

Java:

List<Integer> radixSort(List<Integer> A);

3. Bucket Sort

The last sorting for this challenge (and my favorite one) is one employing probability to sort. Bucket sort assumes that the input data has a uniform distribution, or, in other words, each element has equal probability of having any value of the domain range. An example where this is not true is if you had a list of shoe-sizes of all the people in the university, as although there might be someone with shoe-size 12 (it is in the domain range), it is certainly not as likely as there being one with size 8. Still, there are many cases where the uniform distribution assumption holds.

So how can we exploit that? Imagine that we have one thousand random numbers from zero to one million and that they have a uniform distribution. Thus we expect that the element with index k in the sorted array to have a value around 1000 * k. So we go through the array and put each element x that we encounter in a “bucket” indexed x / 1000 that corresponds to the x / 1000 – th element in the sorted array. Next, for each bucket, if it contains one or less elements, we can append it to the sorted array (initially an empty one). Otherwise we sort it (either using Bucket Sort again, or Insertion Sort, as it performs well on small inputs) and then append it to the sorted array.

As this explanation was a mess, here is an…

Example:

Sort [25, 0, 3, 21, 4, 5, 20, 8, 7, 13, 15]:
Buckets: [0: [0], 1: [3], 2: [4, 5], 3: [8, 7], 4: [], 5: [13], 6: [15], 7: [], 8:[20, 21], 9: [], 10: [25]]
Result: [0, 3, 4, 5, 7, 8, 13, 15, 20, 21, 25].

Another Example:

Sort [10, 27, 7, 15, 16, 24, 13, 17, 19, 23, 14]
Buckets: [0: [7], 1: [], 2:[10], 3:[14, 13], 4: [16, 15], 5: [17], 6: [19], 7: [], 8: [23, 24], 9: [], 10: [27]]
Result: [7, 10, 13, 14, 15, 16, 17, 19, 23, 24, 27]

Test range:

The size of the input array will be less than 107.
The elements of the input array will be 32-bit integers.

Your function is expected to execute for less than 1 second.

Format:

C++:

vector<int> BucketSort(vector<int> &A);

Java:

List<Integer> bucketSort(List<Integer> A);

How to Submit

After you’re done, put the functions in one file called winchal4.cpp or WinChal4.java. In case you are using Java, obviously you need a class. Call it WinChal4 and let it reside in a package called uoeadspractice.<nickname>.challenge4. Also, add a comment with your nickname in the beginning of the file.

When you’re done with that, send the file(s), together with a nickname, and optionally degree, year and university (if it is not University of Edinburgh) to uoeadspractice a t gmail d o t com. The deadline for submitting your code is Sunday 14 October 2012 2359 GMT.

About next week

Since you have to submit your coursework by the end of week 5, I can tell you what challenge 5 would be right now – get a 100 % on your coursework.

Happy Hacking!

– Stan