diff options
| author | Mohammad S Anwar <Mohammad.Anwar@yahoo.com> | 2020-11-07 23:37:45 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-11-07 23:37:45 +0000 |
| commit | 1a71c1dcc6a773afd0388ac136e9d3750837121e (patch) | |
| tree | f81c426803a37526e82f1f937e49a1e8a04c0750 /challenge-085 | |
| parent | 7d72db3996696ec5152426809e4eeec1a1461251 (diff) | |
| parent | efe40d5b692e19806f2a039a8553b24d88b640ff (diff) | |
| download | perlweeklychallenge-club-1a71c1dcc6a773afd0388ac136e9d3750837121e.tar.gz perlweeklychallenge-club-1a71c1dcc6a773afd0388ac136e9d3750837121e.tar.bz2 perlweeklychallenge-club-1a71c1dcc6a773afd0388ac136e9d3750837121e.zip | |
Merge pull request #2713 from Abigail/abigail/week-085
Abigail/week 085
Diffstat (limited to 'challenge-085')
24 files changed, 771 insertions, 0 deletions
diff --git a/challenge-085/abigail/c/ch-1.c b/challenge-085/abigail/c/ch-1.c new file mode 100644 index 0000000000..edfcc8fa03 --- /dev/null +++ b/challenge-085/abigail/c/ch-1.c @@ -0,0 +1,165 @@ +/* + * Challenge + * + * You are given an array of real numbers greater than zero. + * + * Write a script to find if there exists a triplet (a,b,c) such + * that 1 < a+b+c < 2. Print 1 if you succeed otherwise 0. + */ + +/* + * A naieve implementation would be to check each triplet of numbers. + * That leads to a cubic algorithm. + * + * Better is to sort numbers, then for each pair of numbers check whether + * there is a third so that the sum of the three is between 1 and 2. + * If the array is sorted, we can find such a number in O (log N) time, + * resulting in a O (N^2 log N) run time. + * + * Also, if we sort the array (let's call the array a), we can restrict + * our search to triplets a [i], a [j], a[k], with i < j < k. That means, + * we can stop looking for a k if a [i] + 2 * a [j] >= 2, or 3 * a [i] >= 2. + */ + +# include <stdlib.h> +# include <stdio.h> +# include <stdbool.h> +# include <math.h> + +# define MAX 2 +# define MIN 1 +# define DEFAULT_BUF_SIZE 128 +# define BUF_INCREMENT 1.25 /* Increment the buffer size by * + * a quarter each time we run out * + * of memory space. */ +# define NOT_FOUND -1 + +/* + * Compare two floating point values, returning -1, 0, 1 if the first + * is smaller, equal, or larger than the second. + */ +int cmp (const void * a, const void * b) { + float diff = * (float *) a - * (float *) b; + return diff < 0 ? -1 + : diff > 0 ? 1 + : 0; +} + +/* + * Find the index k the largest number in array which is smaller than target, + * and where min <= k < max, or -1 if there is not such a number. + * The numbers in array are sorted. + */ +ssize_t bin_search (float * array, float target, size_t min, size_t max) { + size_t mid = (min + max) / 2; /* In C, dividing integers yields an * + * integer, so there is no need for * + * flooring. */ + + return min >= max || + array [min] >= target ? NOT_FOUND + : min == max - 1 ? min + : array [mid] >= target ? bin_search (array, target, min, mid) + : bin_search (array, target, mid, max); +} + +int main (void) { + /* Arguments for getline () */ + char * line = NULL; + size_t len = 0; + ssize_t length = 0; + + /* We'll store the numbers in array, which we will reuse for each * + * line we're processing. We also need to keep track of how much * + * memory we have allocated for the array. */ + float * array = NULL; + size_t buf_size = DEFAULT_BUF_SIZE; + + /* Give the array some starting memory to work with. */ + if ((array = (float *) malloc (buf_size * sizeof (float))) == NULL) { + fprintf (stderr, "Out of memory\n"); + return (1); + } + + /* + * Iterate over the input, reading one line at a time + */ + while ((length = getline (&line, &len, stdin)) != -1) { + size_t size = 0; /* Number of floats in array. */ + int offset; + float input; + char * line_ptr = line; + + /* + * Read in floats. Note that we don't use use line to pass + * into sscanf, as we modify the first argument in the loop + * (so it always points the part of the string we haven't + * scanned yet). We want to keep the orginal return value + * of getline(), so the memory it points at can be reused. + */ + while (sscanf (line_ptr, "%f%n", &input, &offset) == 1) { + line_ptr += offset; + if (input >= MAX) { /* Not interested in values exceeding */ + break; /* the maximum, as they can never be */ + } /* part of a winning triple. */ + + if (++ size >= buf_size) { + /* Get some more memory. */ + buf_size = (size_t) floorf (buf_size * BUF_INCREMENT); + if ((array = (float *) realloc (array, + buf_size * sizeof (float))) == NULL) { + fprintf (stderr, "Out of memory\n"); + return (1); + } + } + + /* Store it */ + array [size - 1] = input; + } + + qsort (array, size, sizeof (float), cmp); + + /* + * O (N^2 log N) algorithm to find a winning triple, that is, + * indices i < j < k such that + * + * MIN < array [i] + array [j] + array [k] < MAX + * + * We will iterate over all i, j, with i < j, and for each + * such pair, use binary search to find whether there is a k. + * + * We can stop searching if we either have a winning triplet (duh), or + * if 3 * array [i] >= MAX, since array [i] <= array [j] <= array [k]. + * For a given i, we can stop searching for a pair j, k when + * array [i] + 2 * array [j] >= MAX, for the same reason. + */ + bool winner = false; + for (size_t i = 0; i < size && + !winner && + 3 * array [i] < MAX; i ++) { + for (size_t j = i + 1; j < size && + !winner && + array [i] + 2 * array [j] < MAX; j ++) { + float target = MAX - array [i] - array [j]; + ssize_t k = bin_search (array, target, j + 1, size); + if (k != NOT_FOUND) { + /* + * We have a value so that we do not exceed the + * maximum, but we still have to check we're past + * the minimum. Note that array [k] is the largest + * of such numbers (for given i and j), so if we're + * not past the minimum, there is no solution for + * the given i and j. + */ + if (MIN < array [i] + array [j] + array [k]) { + winner = 1; + } + } + } + } + + printf ("%d\n", winner); + + } + free (line); + free (array); +} diff --git a/challenge-085/abigail/input-1-1 b/challenge-085/abigail/input-1-1 new file mode 100644 index 0000000000..90cd707fe8 --- /dev/null +++ b/challenge-085/abigail/input-1-1 @@ -0,0 +1,3 @@ +1.2 0.4 0.1 2.5 +0.2 1.5 0.9 1.1 +0.5 1.1 0.3 0.7 diff --git a/challenge-085/abigail/input-1-2 b/challenge-085/abigail/input-1-2 new file mode 100644 index 0000000000..65fd445445 --- /dev/null +++ b/challenge-085/abigail/input-1-2 @@ -0,0 +1,3 @@ +0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 +1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 +0.5 0.5 0.5 0.5 0.5 0.5 diff --git a/challenge-085/abigail/input-1-3 b/challenge-085/abigail/input-1-3 new file mode 100644 index 0000000000..3d3b7f8ccb --- /dev/null +++ b/challenge-085/abigail/input-1-3 @@ -0,0 +1,4 @@ +1 +1 1 +3 +1.5 0.4 diff --git a/challenge-085/abigail/input-1-4 b/challenge-085/abigail/input-1-4 new file mode 100644 index 0000000000..03db8ce238 --- /dev/null +++ b/challenge-085/abigail/input-1-4 @@ -0,0 +1,2 @@ +.3 .4 .5 .6 .7 .8 +.3 .4 1. 3. 4. diff --git a/challenge-085/abigail/input-1-5 b/challenge-085/abigail/input-1-5 new file mode 100644 index 0000000000..c693829055 --- /dev/null +++ b/challenge-085/abigail/input-1-5 @@ -0,0 +1 @@ +0.8 1.0 0.2 0.8 0.0 0.2 0.6 0.2 0.1 0.7 0.4 0.6 0.4 0.2 0.4 1.0 0.5 0.8 1.0 0.9 0.6 0.8 0.2 0.1 0.3 0.5 0.2 0.0 0.6 0.2 0.7 0.1 0.6 0.9 0.4 0.1 0.9 0.7 0.4 0.2 1.0 0.2 0.8 0.4 0.7 0.9 0.5 0.4 0.3 0.8 1.0 0.6 0.5 0.6 0.1 0.4 0.5 0.3 0.8 0.6 0.2 0.9 0.8 0.8 1.0 0.9 0.6 0.2 0.8 0.3 0.1 0.7 0.1 0.4 0.4 0.9 0.0 0.3 0.1 0.6 0.1 0.0 0.1 0.3 0.3 0.3 0.6 0.3 0.2 0.1 0.5 0.6 0.8 0.8 0.9 0.2 0.7 0.8 0.3 0.2 0.7 0.5 0.0 0.4 0.1 0.4 0.2 0.5 0.4 0.2 0.3 1.0 0.3 0.1 0.2 0.1 0.7 0.0 0.5 0.8 0.6 0.2 1.0 0.8 0.2 0.5 0.9 0.9 0.2 0.1 0.8 0.5 0.8 0.1 0.2 0.9 0.6 1.0 0.2 0.6 0.6 0.6 0.6 0.5 0.2 1.0 0.6 0.1 0.6 0.5 0.3 1.0 0.4 0.2 0.6 0.6 0.0 0.8 0.6 0.6 0.9 0.3 0.7 0.3 0.8 0.1 0.3 0.6 0.4 0.2 0.2 0.4 0.1 1.0 0.5 0.3 0.3 0.3 0.5 1.0 0.7 0.9 0.2 0.5 0.1 0.3 0.4 0.5 0.1 0.4 0.7 0.9 0.3 0.6 0.1 0.6 0.5 0.5 0.8 0.4 0.7 0.7 0.8 0.7 0.3 0.7 0.2 0.7 0.1 1.0 0.3 0.1 0.1 0.7 0.9 0.5 0.1 1.0 0.1 1.0 0.7 0.2 0.4 0.3 0.7 0.8 0.2 0.8 0.5 0.4 0.1 0.4 0.7 1.0 0.4 0.1 0.3 0.4 0.9 0.9 0.1 0.4 0.5 0.8 0.7 0.5 1.0 1.0 1.0 0.7 0.8 0.1 0.3 0.4 0.7 0.9 0.3 0.0 0.2 0.1 0.8 0.4 0.6 0.1 0.1 0.6 0.6 0.8 0.6 0.5 0.5 0.8 0.4 1.0 0.9 0.1 0.4 0.7 1.0 0.1 0.1 0.5 0.3 0.8 0.1 0.2 0.2 0.8 0.5 0.0 0.9 0.9 0.9 0.9 0.4 0.3 0.6 0.8 0.4 0.2 1.0 0.6 1.0 0.1 0.0 0.2 0.6 0.2 0.2 0.7 0.8 0.2 0.1 0.2 0.1 0.0 0.6 1.0 0.2 0.6 0.8 0.9 0.9 0.2 0.4 0.9 0.1 1.0 0.2 0.5 0.5 0.0 0.6 0.4 0.2 0.2 0.0 0.8 0.2 0.1 0.9 0.2 0.2 1.0 0.6 0.8 0.1 0.8 0.0 0.6 0.9 0.4 0.4 0.1 0.2 0.5 0.1 0.5 0.6 0.1 0.8 0.3 0.9 0.4 0.0 0.5 0.3 0.3 0.6 0.5 0.8 0.6 0.1 0.1 0.3 0.2 0.1 0.6 0.3 0.5 0.6 0.7 0.6 0.5 0.6 0.9 0.2 0.8 0.2 0.4 0.3 0.5 0.5 0.6 0.1 0.3 0.6 0.6 0.1 0.9 0.7 0.7 0.9 0.3 0.2 0.3 0.7 0.7 0.4 0.4 0.0 0.4 0.3 0.1 0.3 0.3 0.6 0.0 0.1 0.5 0.9 0.0 0.5 0.3 0.1 0.5 1.0 0.6 0.7 0.6 0.7 0.0 0.9 0.6 0.1 0.6 0.7 0.8 0.5 0.3 0.7 0.1 0.9 0.9 0.8 0.7 0.4 0.1 0.0 0.3 0.4 0.3 0.7 0.6 0.7 0.9 0.1 0.6 0.2 0.3 0.4 1.0 0.9 0.5 1.0 0.4 0.6 0.8 0.9 0.4 0.1 0.0 0.8 0.8 0.6 0.8 0.3 0.6 1.0 0.8 0.8 0.3 0.5 0.1 0.0 0.2 0.5 0.1 0.6 0.1 0.0 0.4 0.1 0.4 0.7 0.8 0.3 1.0 0.7 0.7 0.3 0.4 0.5 0.5 0.2 0.1 1.0 0.5 0.9 0.7 0.8 0.5 0.3 0.8 0.9 0.3 0.8 0.4 0.4 1.0 0.1 0.9 0.3 0.0 0.9 0.1 0.7 0.1 0.6 0.8 0.5 0.7 0.2 0.7 0.2 0.7 0.1 0.4 0.5 0.3 0.9 0.3 0.1 0.4 0.0 0.0 0.9 0.6 0.5 1.0 0.1 0.8 0.1 0.7 0.2 0.2 0.1 0.2 0.7 0.2 0.5 0.6 0.1 0.7 0.1 1.0 0.6 0.4 0.9 0.4 0.1 0.9 0.8 0.5 0.9 0.3 0.4 0.7 0.2 0.3 0.1 0.7 0.4 0.9 0.2 0.6 0.8 0.1 0.8 0.2 0.1 0.9 0.3 0.2 0.3 0.6 0.6 0.4 0.3 0.5 0.4 0.1 0.9 0.5 0.1 0.3 0.6 0.3 0.7 0.8 0.7 0.4 0.4 0.1 0.4 0.7 0.6 0.2 0.9 0.1 0.2 0.1 1.0 0.0 0.1 0.6 0.9 0.0 0.2 0.4 0.7 0.9 0.4 0.2 0.3 0.9 0.9 0.6 0.5 0.4 0.5 0.2 0.1 0.4 0.1 0.7 0.4 0.8 0.7 0.8 0.3 0.2 0.4 0.1 0.1 0.5 0.5 0.5 0.2 0.4 0.1 0.0 0.5 0.9 0.5 0.7 0.9 0.7 0.8 0.9 0.2 0.2 0.6 0.4 0.4 0.2 1.0 0.8 0.3 0.2 0.4 0.7 0.7 0.9 0.7 0.4 0.7 0.2 1.0 0.4 0.1 0.0 0.7 0.1 0.6 0.6 0.7 0.9 0.8 0.4 0.2 0.7 0.1 0.0 0.1 0.9 0.5 0.7 0.8 0.5 0.6 0.4 1.0 0.2 0.6 0.4 0.2 0.3 0.3 0.6 0.9 0.1 0.7 0.9 0.8 0.2 0.7 0.9 0.7 0.8 0.6 0.3 0.0 0.2 0.6 0.1 0.7 0.3 0.9 0.4 0.6 0.2 0.6 0.5 0.3 0.7 0.2 0.8 0.7 0.7 1.0 0.6 0.0 0.8 0.6 0.3 0.2 0.1 0.4 0.6 0.6 0.5 0.9 0.9 0.3 0.0 0.3 0.4 0.7 0.3 0.9 0.7 0.2 0.2 0.8 0.8 0.3 1.0 0.0 0.3 0.8 0.8 0.7 0.9 0.6 0.2 0.7 0.3 0.1 1.0 0.2 0.3 0.9 0.6 0.6 0.2 0.9 0.8 0.8 0.6 0.6 0.7 0.5 0.1 0.4 1.0 0.1 0.9 0.5 0.0 0.0 0.8 0.4 0.2 0.5 0.6 0.4 0.8 0.1 0.7 0.8 0.7 0.9 0.2 0.6 0.2 0.5 0.8 0.3 1.0 0.7 0.2 0.7 0.7 0.1 0.7 0.1 0.1 1.0 0.5 0.9 0.9 0.1 0.0 0.4 0.4 0.3 0.6 0.7 0.9 0.7 0.1 0.3 0.7 0.3 0.5 0.7 0.8 0.8 0.6 0.4 0.1 0.7 0.2 0.8 0.8 0.1 0.6 0.7 0.2 0.9 0.9 0.1 0.7 0.4 0.7 0.8 0.5 0.5 0.4 0.7 0.8 0.8 1.0 1.0 0.4 0.5 0.8 0.5 0.1 0.8 0.9 0.4 0.1 0.6 0.4 0.4 0.4 0.5 0.2 0.7 0.8 0.8 0.9 0.2 0.3 0.7 0.8 0.0 0.0 0.1 0.5 0.7 0.4 0.8 0.6 0.7 0.7 0.5 0.6 0.3 0.5 0.8 0.6 0.3 0.8 0.9 0.5 0.8 1.0 0.6 1.0 0.4 0.9 0.0 0.2 0.2 0.8 0.1 0.2 0.5 0.7 0.5 0.7 0.5 0.2 0.8 0.7 0.7 0.9 0.4 0.2 0.2 0.9 0.8 0.2 0.4 1.0 0.0 0.7 0.6 0.1 0.7 0.8 0.6 0.4 0.4 1.0 0.6 0.5 0.7 0.3 0.3 0.7 0.8 0.1 0.1 0.7 0.2 0.7 0.2 0.1 0.1 0.4 0.4 0.4 0.4 0.1 0.7 0.2 0.8 0.2 0.7 0.5 0.9 0.4 0.8 0.5 0.3 0.4 diff --git a/challenge-085/abigail/input-2-1 b/challenge-085/abigail/input-2-1 new file mode 100644 index 0000000000..3a68f04570 --- /dev/null +++ b/challenge-085/abigail/input-2-1 @@ -0,0 +1,3 @@ +8 +15 +125 diff --git a/challenge-085/abigail/input-2-2 b/challenge-085/abigail/input-2-2 new file mode 100644 index 0000000000..9a19645eef --- /dev/null +++ b/challenge-085/abigail/input-2-2 @@ -0,0 +1,2 @@ +12201900399479668244827490915525641902001 +1256795741146405829217231564299141115906103 diff --git a/challenge-085/abigail/input-2-3 b/challenge-085/abigail/input-2-3 new file mode 100644 index 0000000000..eb6bdd5323 --- /dev/null +++ b/challenge-085/abigail/input-2-3 @@ -0,0 +1,2 @@ +2203419458138249913957177758821 +248785887598931659534990983570720289 diff --git a/challenge-085/abigail/input-2-4 b/challenge-085/abigail/input-2-4 new file mode 100644 index 0000000000..c2ee65b09c --- /dev/null +++ b/challenge-085/abigail/input-2-4 @@ -0,0 +1,10 @@ +2535301200456458802993406410751 +2535301200456458802993406410752 +2535301200456458802993406410753 +13915193059764305937984450503671774362956903094026 +13915193059764305937984450503671774362956903094027 +13915193059764305937984450503671774362956903094028 +3291009114642412084309938365114701009965471731267159726697218047 +3291009114642412084309938365114701009965471731267159726697218048 +3291009114642412084309938365114701009965471731267159726697218049 +478982867314193079343103971012905274780918889411529711276449080795491360573329941179894329618422913840217769989606002186784087122515410466421746099971911425217863660595506199897260676180132923869021199030846190814296645838293654953461447739891770786560456351897698413448956040891252504107001464301214129363916878598502352307571733754319063127928219815197533791143169704045528663736668573652473577217339249737995657450566765584821808491610093271865028511111099234263033059912119238910312977244859782573291554561945761658348522571502930050519241090096163802044817062082245385415413472602822462327994217324345808931910453620601121608190937504657725464045616942932685263613693650331152442378889986048 diff --git a/challenge-085/abigail/output-1-1.exp b/challenge-085/abigail/output-1-1.exp new file mode 100644 index 0000000000..5df04e8c46 --- /dev/null +++ b/challenge-085/abigail/output-1-1.exp @@ -0,0 +1,4 @@ +# Given examples +1 +0 +1 diff --git a/challenge-085/abigail/output-1-2.exp b/challenge-085/abigail/output-1-2.exp new file mode 100644 index 0000000000..eaa3485143 --- /dev/null +++ b/challenge-085/abigail/output-1-2.exp @@ -0,0 +1,4 @@ +# All the same +0 +0 +1 diff --git a/challenge-085/abigail/output-1-3.exp b/challenge-085/abigail/output-1-3.exp new file mode 100644 index 0000000000..5a683ff879 --- /dev/null +++ b/challenge-085/abigail/output-1-3.exp @@ -0,0 +1,5 @@ +# Arrays too short +0 +0 +0 +0 diff --git a/challenge-085/abigail/output-1-4.exp b/challenge-085/abigail/output-1-4.exp new file mode 100644 index 0000000000..4fbed60ade --- /dev/null +++ b/challenge-085/abigail/output-1-4.exp @@ -0,0 +1,3 @@ +# Short decimals +1 +1 diff --git a/challenge-085/abigail/output-1-5.exp b/challenge-085/abigail/output-1-5.exp new file mode 100644 index 0000000000..73b8267686 --- /dev/null +++ b/challenge-085/abigail/output-1-5.exp @@ -0,0 +1,2 @@ +# Lots of floats +1 diff --git a/challenge-085/abigail/output-2-1.exp b/challenge-085/abigail/output-2-1.exp new file mode 100644 index 0000000000..5df04e8c46 --- /dev/null +++ b/challenge-085/abigail/output-2-1.exp @@ -0,0 +1,4 @@ +# Given examples +1 +0 +1 diff --git a/challenge-085/abigail/output-2-2.exp b/challenge-085/abigail/output-2-2.exp new file mode 100644 index 0000000000..3ef9e501d9 --- /dev/null +++ b/challenge-085/abigail/output-2-2.exp @@ -0,0 +1,3 @@ +# Large numbers +1 +0 diff --git a/challenge-085/abigail/output-2-3.exp b/challenge-085/abigail/output-2-3.exp new file mode 100644 index 0000000000..8f19c4850c --- /dev/null +++ b/challenge-085/abigail/output-2-3.exp @@ -0,0 +1,3 @@ +# Numbers with 6 digit prime factors +1 +0 diff --git a/challenge-085/abigail/output-2-4.exp b/challenge-085/abigail/output-2-4.exp new file mode 100644 index 0000000000..cb782bcd04 --- /dev/null +++ b/challenge-085/abigail/output-2-4.exp @@ -0,0 +1,11 @@ +# Large exponents +0 +1 +0 +0 +1 +0 +0 +1 +0 +1 diff --git a/challenge-085/abigail/perl/ch-1.pl b/challenge-085/abigail/perl/ch-1.pl new file mode 100644 index 0000000000..b03f8ae2ba --- /dev/null +++ b/challenge-085/abigail/perl/ch-1.pl @@ -0,0 +1,101 @@ +#!/opt/perl/bin/perl + +use 5.032; + +use strict; +use warnings; +no warnings 'syntax'; + +use experimental 'signatures'; +use experimental 'lexical_subs'; + +# +# Challenge +# +# You are given an array of real numbers greater than zero. +# +# Write a script to find if there exists a triplet (a,b,c) such +# that 1 < a+b+c < 2. Print 1 if you succeed otherwise 0. +# + +# +# A naieve implementation would be to check each triplet of numbers. +# That leads to a cubic algorithm. +# +# Better is to sort numbers, then for each pair of numbers check whether +# there is a third so that the sum of the three is between 1 and 2. +# If the array is sorted, we can find such a number in O (log N) time, +# resulting in a O (N^2 log N) run time. +# +# Also, if we sort the array (let's call the array a), we can restrict +# our search to triplets a [i], a [j], a[k], with i < j < k. That means, +# we can stop looking for a k if a [i] + 2 * a [j] >= 2. +# + +my $MIN = 1; +my $MAX = 2; + +# +# Find the largest number in $array which is smaller than $target, +# with index k, $min <= k < $max, or undef if there is not such a number. +# +sub binsearch ($array, $target, $min = 0, $max = @$array) { + my $mid = int (($min + $max) / 2); + + return $min >= $max || + $$array [$min] >= $target ? undef + : $min == $max - 1 ? $$array [$min] + : $$array [$mid] >= $target ? binsearch ($array, $target, $min, $mid) + : binsearch ($array, $target, $mid, $max) +} + + +LINE: while (<>) { + # + # Read the array of numbers, sort, and store them. + # + my $array = [sort {$a <=> $b} /[0-9.]+/g]; + + # + # Iterate over all pairs + # + for (my $i = 0; $i < @$array; $i ++) { + # + # If 3 * $$array [$i] >= $MAX, we cannot have any solutions, + # as $$array [$j] >= $$array [$i] for $j > $i. + # + last if 3 * $$array [$i] >= $MAX; + for (my $j = $i + 1; $j < @$array; $j ++) { + # + # If the sum of the first number and twice the second + # exceeds the maximum, no triples with this pair will do. + # + last if $$array [$i] + 2 * $$array [$j] >= $MAX; + my $sum2 = $$array [$i] + $$array [$j]; + + # + # Find a third number, if any. If we can find a suitable number, + # it means we either have reached the end of the array, or all + # numbers make it exceed the maximum sum. + # + my $third = binsearch $array, $MAX - $sum2, $j + 1; + last unless defined $third; + # + # We still need to check whether we have exceeded the minimum value. + # + if ($MIN < $sum2 + $third) { + # + # Found suitable triple! + # + say 1; + next LINE; + } + } + } + # + # No suitable triples found. + # + say 0; +} + +__END__ diff --git a/challenge-085/abigail/perl/ch-2.pl b/challenge-085/abigail/perl/ch-2.pl new file mode 100644 index 0000000000..effa16dab2 --- /dev/null +++ b/challenge-085/abigail/perl/ch-2.pl @@ -0,0 +1,186 @@ +#!/opt/perl/bin/perl + +use 5.032; + +use strict; +use warnings; +no warnings 'syntax'; + +use experimental 'signatures'; +use experimental 'lexical_subs'; + +use Math::BigInt; + +# +# Challenge +# +# You are given a positive integer $N. +# +# Write a script to find if it can be expressed as a ^ b where a > +# 0 and b > 1. Print 1 if you succeed otherwise 0. +# + +# +# We solve this *not* by factoring $N, but by searching for an nth root +# which gives an integer. +# +# Note that if $N is of the form a ^ b (a > 0, b > 1, a, b integer), then +# there is a solution of the form q ^ p, with q, p integer and p prime. +# (Proof: Let p be a prime factor of b, so b == p * c, for some c >= 1. +# Then a ^ b == a ^ (c * p) == (a ^ c) ^ p. Then let q = a ^ c). +# +# So, we want to find a prime p, such that the p-th root of $N is an integer. +# Now, if $N > 1, and if $N == q ^ p, then q >= 2. Hence, p <= log_2 N. +# So, we want to test all primes less than log_2 N. (We will test some +# composite numbers as well, but we won't skip any primes). +# +# How do we test whether the p-th root is an integer? We will be making use +# of Math::BigInt. broot (p) gives the p-th root, but rounded to an integer. +# If we can do a round trip, that is raising the rounded p-th root to the p-th +# power, and be back in $N again, we have a winner. +# + +# +# A little class we use to iterate over all primes, and some composite. +# +# Let p_i be the ordered set of all primes, p_i < p_j, iff i < j. +# +# Let P be the product of first n primes (p_1 * ... * p_n). +# +# Let S be the set of primes p_j, j > n, p_j <= P + 1. +# +# Then all primes p_j, j > n, are of the form: +# +# k * P + l, k >= 0, l in S [1] +# +# (But not all numbers of that form are prime) +# +# For details, see https://en.wikipedia.org/wiki/Wheel_factorization +# +# +# We will use the class Wheel below to iterate over the set +# +# p_1, .., p_n, k * P + 1, k >= 0, l in S +# +# This will iterate over all primes, and some composites. +# +# In particular, we pick n == 3, so p_1 == 2, p_2 == 3, and p_3 == 5. +# + +# +# (Of course, this is a little overkill. 2^1000 is a number of over 300 +# digits, and it's unlikely the test inputs for this challenge will have +# numbers going that large. We could easily list the 168 prime numbers +# up to 1000 instead. But there is no fun in that! And just to prove a +# a point, our test case includes 2^2311, a 696 digit number; 2311 is a +# Euclid prime (2311 = 2 * 3 * 5 * 7 * 11 + 1)). +# + +package Wheel { + use List::Util 'product'; + use Hash::Util::FieldHash 'fieldhash'; + use overload '0+' => \&numify, + '++' => \&inc, + ; + + my @primes = (2, 3, 5); # Base primes + my $product = product @primes; # Product of base primes + + # + # Use a sieve to find all primes up to $product - 1. + # + my @sieve = (1) x ($product + 2); + $sieve [$_] = 0 for 0, 1; + for (my $i = 2; $i <= sqrt $product; $i ++) { + next unless $sieve [$i]; + for (my $j = $i * $i; $j <= $product; $j += $i) { + $sieve [$j] = 0; + } + } + # + # Remove base primes + # + $sieve [$_] = 0 for @primes; + + my @batch = grep {$sieve [$_]} keys @sieve; # Primes upto $product, other + # than the base primes, and + # $product + 1 (which may, or + # may not be prime). + # These are the l's in [1]. + + fieldhash my %index; # k in [1]. + fieldhash my %queue; # Next numbers to be returned. + + # + # Initialize the object. + # + sub new ($class) {bless \do {my $var} => $class} + sub init ($self) { + $index {$self} = 0; + $queue {$self} = [@primes]; + $self; + } + + # + # Overload methods + # + + # + # Increment the number. We're shifting of the first number of the + # queue, and we replenish the queue if it's empty. + # + sub inc ($self, $, $) { + shift @{$queue {$self}}; + if (!@{$queue {$self}}) { + $queue {$self} = [map {$index {$self} * $product + $_} @batch]; + $index {$self} ++; + } + $self; + } + + # + # Current value: first element in the queue. + # + sub numify ($self, $, $) { + $queue {$self} [0]; + } +} + +NUMBER: while (<>) { + # + # Read the number + # + my $N = Math::BigInt:: -> new ($_); + + # + # Special case $N == 1 + # + if ($N == 1) { + say 1; + next; + } + + # + # Maximum value of the exponent. + # + my $max_exponent = $N -> copy -> blog (2); + + # + # $exponent will the number(s) we try as exponent. + # + my $exponent = Wheel:: -> new -> init; + + while ($exponent <= $max_exponent) { + if ($N == $N -> copy -> broot ($exponent) -> bpow ($exponent)) { + say 1; + next NUMBER; + } + + $exponent ++; + } + say 0; +} + + + +__END__ diff --git a/challenge-085/abigail/sql/ch-1.sql b/challenge-085/abigail/sql/ch-1.sql new file mode 100644 index 0000000000..796f7f1a86 --- /dev/null +++ b/challenge-085/abigail/sql/ch-1.sql @@ -0,0 +1,16 @@ +-- +-- See the file ch-1.table for the definition of the used table. +-- +-- Assumes each number of the input is on a separate row. +-- + +SELECT COUNT(*) + FROM (SELECT 1 + FROM Numbers t1, + Numbers t2, + Numbers t3 + WHERE t1 . id > t2 . id + AND t2 . id > t3 . id + AND 1 < t1 . value + t2 . value + t3 . value + AND t1 . value + t2 . value + t3 . value < 2 + LIMIT 1) diff --git a/challenge-085/abigail/sql/ch-1.table b/challenge-085/abigail/sql/ch-1.table new file mode 100644 index 0000000000..bb61916024 --- /dev/null +++ b/challenge-085/abigail/sql/ch-1.table @@ -0,0 +1,4 @@ +CREATE TABLE Numbers ( + id integer PRIMARY KEY, + value float +) diff --git a/challenge-085/abigail/test.pl b/challenge-085/abigail/test.pl new file mode 100755 index 0000000000..74cf691f6e --- /dev/null +++ b/challenge-085/abigail/test.pl @@ -0,0 +1,230 @@ +#!/opt/perl/bin/perl + +# +# Test the solutions. Either call it with the directory name you +# want to test in, or call it as "../test.pl" from within the directory. +# + +use 5.032; + +use strict; +use warnings; +no warnings 'syntax'; + +chdir ".." if -f "../test.pl"; + +use experimental 'signatures'; + +use Test::More; +use DBI; + + +my %languages = ( + Perl => { + exe => "/opt/perl/bin/perl", + ext => "pl", + }, + JavaScript => { + exe => "/usr/local/bin/node", + ext => "js", + dir => "node", + }, + bc => { + exe => "/usr/bin/bc", + ext => "bc", + filter => 's/.*/main($&)/', + }, + awk => { + exe => "/usr/bin/awk", + ext => "awk", + args => ["-f"], + }, + C => { + exe => "/usr/bin/cc", + ext => "c", + dir => "c", + }, + SQL => { + ext => "sql", + }, +); + +my $perl_exe = $languages {Perl} {exe}; + +foreach my $challenge (1, 2) { + my ($dbh, $query, $tables_info); # Only for SQL tests. + + my @inputs = <input-$challenge-*> or next; + subtest "Challenge $challenge" => sub { + foreach my $language (sort keys %languages) { + my $info = $languages {$language}; + my $exe = $$info {exe}; + my $ext = $$info {ext}; + my $dir = $$info {dir} // lc $language; + my @args = @{$$info {args} // []}; + my $filter = $$info {filter} // ''; + my $ext_out = $$info {ext_out} // "out"; + my $source = "$dir/ch-$challenge.$ext"; + my $compiled; + next unless -r $source; + + # + # C requires special handling. The source needs to be compiled. + # + if ($language eq "C") { + $compiled = $source =~ s/\.$ext$/.$ext_out/r; + system $exe, "-o", $compiled, $source; + } + + # + # SQL requires requires creating an in-memory database, + # and loading some tables. For that, we need a .tables + # file. We also read the actual query at this time. + # + if ($language eq "SQL") { + my $tables = $source =~ s/\.\Q$ext\E$/.table/r; + |
