The key to making the problem tractable was to notice that though the problem asks for the minimal Product-Sum numbers for a given k (size of the set for which it is a PS number), the easier domain was to look at numbers and find for what k values they are product sum numbers. When I made this switch, I when from minutes to seconds in the speed of my code.
However, the script that I ran to initially compute the answer was written in python, for ease, but I knew I had to convert to another language eventually for the language challenge. I ended up going with C, and while C works, I ran into...a bit of an issue. In Python I was just using lists and wasn't aware of just how much memory was flying around, but when I wrote a solution in C I found out that the solution actually involves allocating many million-element arrays...so after pushing the size of my arrays and making sure to allocate and free memory well to avoid seg faults, I eventually got to a working solution, which is below. Runs in about 16 seconds in my machine. Much of that time is probably spent in malloc.
#include<stdio.h> #include<stdlib.h> int BOUND = 12000; /** Gets the sums of all factoriations of n, minus the number of terms in the * factorization. This is most of the k-value for which n is a Product-Sum number * k-value = n - factorizationSum*/ /** Admittably not the most efficient of code...this is what I get for * trying to transfer code originally written in python */ void getAllFactorizationSums(int n, int includeself, int maxlength, int* output, int* outputLength) { /**Don't look at exceptionally long factorizations*/ if (maxlength == 0) { output[0] = -1; *outputLength = 1; return; } int* returnValue = (int*) malloc(sizeof(int) * 15 * BOUND); int rvLength = 0; int f; for (f = 2; f*f <= n; ++f) { if (n % f == 0) { getAllFactorizationSums(n / f, 1, maxlength - 1, output, outputLength); int j; for (j = 0; j < *outputLength; ++j) { int fSum = output[j]; if (fSum != -1) { returnValue[rvLength++] = fSum + f - 1; } } } } if (includeself) { returnValue[rvLength++] = n - 1; } //copy back to output int i; for (i = 0; i < rvLength; ++i) { output[i] = returnValue[i]; } *outputLength = rvLength; free(returnValue); } int min(int x, int y) { return x < y ? x : y; } int main(int argc, char ** argv) { int* productSumsForK = (int*) malloc(sizeof(int) * (BOUND + 1)); productSumsForK[0] = 0; productSumsForK[1] = 0; int i; /**Initialize with upper bounds*/ for (i = 2; i <= BOUND; ++i) { productSumsForK[i] = 2 * i; } /**Allocate lots of space...most of it actually gets used!*/ int* factorizationSums = (int*) malloc(sizeof(int) * 15 * BOUND); int fsLength = 0; int N; for (N = 4; N <= 2*BOUND; ++N) { getAllFactorizationSums(N, 0, 15, factorizationSums, &fsLength); for (i = 0; i < fsLength; ++i) { int kIndex = N - factorizationSums[i]; if (kIndex <= BOUND) { productSumsForK[kIndex] = min(productSumsForK[kIndex], N); } } } //Now, we need to convert to a set to print the answer char set[BOUND/4]; for (i = 0; i < BOUND/4; ++i) { set[i] = 0; } for (i = 0; i <= BOUND; ++i) { int psNum = productSumsForK[i]; set[psNum / 8] |= (1 << (psNum % 8)); } int sum = 0; for (i = 0; i < 2*BOUND; ++i) { if ((set[i / 8] >> (i % 8)) & 1) { sum += i; } } printf("%d\n", sum); return 0; }
No comments:
Post a Comment