Solution: Strange Coins There are a number of different ways to solve this problem. We will run through a few of them before we discuss what the fastest way to solve the problem might be. Let’s assume that the present costs exactly 1000 Olympios. (a) One of the first things you might try doing is to think about the different test cases that might be used to trick you program. A very simple case might be if only one coin was needed. Coins = {10, 50, 99, 100, 76, 194, 32, 1000, 7, 995} Here, the 1000 coin will be enough. So the answer is one. (b) Another test case might need all the coins. So the total sum of coins is 1000. Coins = {10, 10, 10, 20, 50, 700, 100, 99, 1} So the answer is 9 (nine coins needed). (c) Another test might include coins of value larger than the gift price. If the gift price was 100, there might be a case like this: Coins = {200, 250, 101, 111, 217} In a case like that, we can ignore coins of value greater than the price of the present. (Incidentally, the example above has no solution) It would seem from examples (a) and (b) that the solution can be anything from one coin, up to N coins (where N is the total number of coins in his pocket). So our program could try all the combinations of coins to see if any of them added up to the exact price. Well, how many combinations are there? For each combination, we will choose a subset of the N coins. For each coin in his pocket, Lionel can choose to either include it in the subset or not. That means he has 2 choices with each coin. This gives a total of 2^N (2 to the power of N) combinations. For example, if Coins = {1,2,7} N = 3 coins We have 2^3 = 8 possible combinations [(no coins = 0), (1), (1,2), (1,7), (2), (2,7), (1,2,7), (7)] When there are 40 coins in his pocket, that will mean 2^40 combinations. 2^40 = 1,099,511,627,776 !!! Ok, so our program that checks all combinations wont work for the big test cases, but it might get us some points. So how would we go about writing a program to try all the possibilities? One simple way is to use ‘recursion’. Let’s keep an array called // This array indicates if a particular coin is being used in our final total int used[40] // This array stores the value of each coin int value[40] // This stores our current best solution for the minimum number of coins int bestmin = 999; // This is the present cost int target; int calculate_total(void) { int i, total = 0; for (i=0 ; i<N ; i++) if (used[i] == 1) total = total + value[i]; return total; } int count_coins(void) { int i, total = 0; for (i=0 ; i<N ; i++) if (used[i] == 1) total++; return total; } void find_min(int curr) { if (calculate_total() == target) bestmin = count_coins(); if (curr >= N) return; used[curr] = 0; find_min(curr+1); used[curr] = 1; find_min(curr+1); } A lot of the initialisation and data input code has been left out but you can hopefully see the core of the technique. The ‘find_min’ function is the bit that does all the work. It is a ‘recursive’ function, which means that it calls itself! Ok, so let’s see how we might come to an effective solution. We know the limits on the values of the coins (40) and the number of coins (250). So our maximum total is 40x250 = 10,000. If we keep an array of size 10,000 and in it we will store ‘1’ at position k if it is possible to use the coins we have to add up to exactly k Olympios, ‘0’ if not. To construct this array, we initially set all values to 0. Then we read in each coin value, v, in turn and add this value to every k that has a ‘1’ in the array. So if there is a ‘1’ at position k, set position k+v to ‘1’. Also, set position ‘v’ to ‘1’. Let’s say our coins are {2, 7, 1}. On the next page, we see three rows: (a) k value (b) got_total array (c) min_coins array Initial array: (a)1 2 (b)0 0 (c)99 99 3 0 99 4 0 99 5 0 99 6 0 99 7 0 99 8 0 99 9 0 99 10 0 99 11 0 99 12 0 99 Read in 2 (a)1 2 (b)0 1 (c)99 1 3 0 99 4 0 99 5 0 99 6 0 99 7 0 99 8 0 99 9 0 99 10 0 99 11 0 99 12 0 99 Read in 7 (a)1 2 (b)0 1 (c)99 1 3 0 99 4 0 99 5 0 99 6 0 99 7 1 1 8 0 99 9 1 2 10 0 99 11 0 99 12 0 99 read in 1 (a)1 2 (b)1 1 (c)1 1 3 1 2 4 0 99 5 0 99 6 0 99 7 1 1 8 1 2 9 1 2 10 1 3 11 0 99 12 0 99 So now we know what totals are possible with our coins (from the (b) rows). We still need to know what the minimum number of coins is to get each total. To solve this, we use another array which will store the minimum number of coins; initialised to 99 (or any big number greater than N). This is the array shown in (c) above. This technique is based on ‘dynamic programming’, a method that used pre-calculated information to do things faster. The algorithm is shown below: Initialise arrays Read in value, v For k = 10001 downto 1 if (got_total[k] == 1) Set got_total[k+v] = 1 Set min_coins[k+v] = min(min_coins[k+v], min_coins[k]+1); Set got_total[v] = 1 Set min_coins[v] = 1 It’s important to go backwards in the ‘for’ loop, because otherwise we might add the same coin twice. Solution: The King-Maker In this problem there a few things we can notice to make the solution simpler. First, if two factions support the same candidate, we can combine them into one. For example, if part of the input is: 20 13 10 20 8 7 We can combine that into one faction: 20 21 17 (i.e. If you don’t elect candidate 20, we will attack you with 21 tanks, if you do elect them, we will aid you with 17 tanks) We start by assuming we have not chosen anyone for the positions – so everyone is against us! Example input: 5 1 10 10 2 20 10 3 5 10 463 573 So there are (10+20+5+6+7 =) 48 tanks opposing us. Let’s give us a starting score of -48. Now, for each candidate, we can calculate how this score will change if we pick them. For example, for candidate 1, if we choose this person, our score will go up by 20 (10 less tanks opposing, 10 more with us). So, a candidate’s score is simply the sum of their ‘opposing’ + ‘supporting’ values. After calculating the scores, we then just need to pick the top 3 candidates. If two candidates have the same score, simply choose the candidate with the lower ID. This will ensure that the ‘sum of candidates IDs’ is minimised if there are multiple solutions. The algorithm is quite short: // candidates and tank numbers int C[30000], J[30000], K[30000]; // number of statements int S; int score; // candidate score int cand[10000]; // starting score score=0; for (i=0 ; i<S ; i++) score = score – J[i]; // initialise array for (i=0 ; i<10000 ; i++) cand[i] = 0; // Note: we use C[i]-1 because arrays start from zero for (i=0 ; i<S ; i++) cand[C[i]-1] += (J[i] + K[i]); All that’s left now is to choose the 3 candidates with the highest scores. Solution: Prime Factors All we need to do here is to count the number of prime factors for every number and store the one with the most prime factors (and if two of them have the same number of prime factors, choose the smallest). So how do we count the prime factors of a number? The simplest way is to try each prime and if it divides the number, then it’s a factor! So how do we calculate the primes? There are a number of ways to do it, but here we can do a brute force approach because we are not using very big numbers. To calculate the primes int nprimes; int primes[1024]; nprimes = 2; primes[0] = 2; for (i=3 ; i<1024 ; i++) { isprime = true; for (j=0 ; j<nprimes ; j++) if ((i % primes[j]) == 0) { isprime = false; break; } if (isprime) { primes[nprimes] = I; nprimes++; } } To count the number of prime factors: count = 0; For (i=0 ; i<nprimes ; i++) If ((num % primes[i]) == 0) count++; printf(“%d has %d prime factors\n”, num, count); A more efficient way to do this problem could be to remember that the input numbers will never be more than 1024. You may know that any non-prime will have a prime factor that is less or equal to than the square root of itself (and if you don’t … now you do!). So any non-prime between 2 and 1024 will have a prime factor less than or equal to sqrt(1024) = 32. So this list of primes is {2,3,5,7,11,13,17,19,23,29,31}. Some examples: Let’s take 407. If we try to divide these primes into 407, we find that 11 is a factor. 407 / 11 = 37. Since 37 is not divisible by any of the primes, it must be prime. So 407 has 2 prime factors. Take 961; 31 divides it. 961/31 = 31. Now, 31 can be divided by 31: 31/31 = 1. So it also has 2 prime factors. Take 997. It cannot be divided by any of the primes in the list, so it must be prime itself. Therefore, 997 has one prime factor. This improvement in efficiency is not significant in this problem and is also tricky to code (to get it right). In problems like this, I would recommend the reliable but inefficient algorithm because you can otherwise waste precious time debugging. Solution: Above Average In this problem, we have to read through the list twice (first to calculate the average, then second to count how many are above it). To calculate the average use a variable ‘count’ to add up all the numbers. Then divide it by the total number of numbers. It doesn’t matter that it is rounded down to the nearest integer. One the next pass, set a counter to zero, then simply compare every number to the average and if it’s greater, then increment your counter. Code shown below: #include <stdio.h> int main(void) { int score[10000]; // open input file FILE *fin = fopen("average.in", "rt"); if (fin == NULL) { fprintf(stderr, "File not found: Average.in\n"); return -1; } // read input file // and calculate total sum int i, N, sum; fscanf(fin, "%d", &N); sum=0; for (i=0 ; i<N ; i++) { fscanf(fin, "%d", &score[i]); sum += score[i]; } fclose(fin); // calculate average int average = sum / N; // count above average int count = 0; for (i=0 ; i<N ; i++) { if (score[i] > average) count++; } // output count FILE *fout = fopen("average.out", "wt"); fprintf(fout, "%d\n", count); fclose(fout); return 0; }