Add more solutions

Added solutions for problems 76, 77, 78, 79 and 80 in C and python.
This commit is contained in:
daniele 2019-09-30 12:47:03 +02:00
parent b652bd147f
commit 579d86d267
Signed by: fuxino
GPG Key ID: 6FE25B4A3EE16FDA
14 changed files with 793 additions and 12 deletions

50
C/keylog.txt Normal file
View File

@ -0,0 +1,50 @@
319
680
180
690
129
620
762
689
762
318
368
710
720
710
629
168
160
689
716
731
736
729
316
729
729
710
769
290
719
680
318
389
162
289
162
718
729
319
790
680
890
362
319
760
316
729
380
319
728
716

View File

@ -6,8 +6,8 @@
* 2 + 2 + 1
* 2 + 1 + 1 + 1
* 1 + 1 + 1 + 1 + 1
How many different ways can one hundred be written as a sum of at least two positive integers?*/
*
* How many different ways can one hundred be written as a sum of at least two positive integers?*/
#include <stdio.h>
#include <stdlib.h>
@ -32,7 +32,7 @@ int main(int argc, char **argv)
/* The number of ways a number can be written as a sum is given by the partition function
* (-1 because the partition function includes also the number itself).
* The function is implemented in projecteuler.c*/
n = partition_fn(100, partitions) - 1;
n = partition_fn(100, partitions, -1) - 1;
free(partitions);

83
C/p077.c Normal file
View File

@ -0,0 +1,83 @@
/* It is possible to write ten as the sum of primes in exactly five different ways:
*
* 7 + 3
* 5 + 5
* 5 + 3 + 2
* 3 + 3 + 2 + 2
* 2 + 2 + 2 + 2 + 2
*
* What is the first value which can be written as the sum of primes in over five thousand different ways?*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include "projecteuler.h"
int count(int value, int n, int i, int target);
int primes[100];
int main(int argc, char **argv)
{
int i, j, n;
double elapsed;
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
/* Generate a list of the first 100 primes.*/
for(i = 0, j = 0; j < 100; i++)
{
if(is_prime(i))
{
primes[j++] = i;
}
}
i = 1;
/* Use a function to count the number of prime partitions for
* each number >= 2 until the one that can be written in over
* 5000 ways is found.*/
while((n = count(0, 0, 0, ++i)) <= 5000);
clock_gettime(CLOCK_MONOTONIC, &end);
elapsed = (end.tv_sec - start.tv_sec) + (double)(end.tv_nsec - start.tv_nsec) / 1000000000;
printf("Project Euler, Problem 77\n");
printf("Answer: %d\n", i);
printf("Elapsed time: %.9lf seconds\n", elapsed);
return 0;
}
/* Function using a simple recursive brute force approach
* to find all the partitions.*/
int count(int value, int n, int i, int target)
{
int j;
for(j = i; j < 100; j++)
{
value += primes[j];
if(value == target)
{
return n + 1;
}
else if(value > target)
{
return n;
}
else
{
n = count(value, n, j, target);
value -= primes[j];
}
}
return n;
}

44
C/p078.c Normal file
View File

@ -0,0 +1,44 @@
/* Let p(n) represent the number of different ways in which n coins can be separated into piles.
* For example, five coins can be separated into piles in exactly seven different ways, so p(5)=7.
*
* OOOOO
* OOOO O
* OOO OO
* OOO O O
* OO OO O
* OO O O O
* O O O O O
*
* Find the least value of n for which p(n) is divisible by one million.*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "projecteuler.h"
#define N 1000000
int main(int argc, char **argv)
{
int i = -1;
long int partitions[N] = {0};
double elapsed;
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
/* Using the partition function to calculate the number of partitions,
* giving the result modulo N.*/
while(partition_fn(++i, partitions, N) != 0);
clock_gettime(CLOCK_MONOTONIC, &end);
elapsed = (end.tv_sec - start.tv_sec) + (double)(end.tv_nsec - start.tv_nsec) / 1000000000;
printf("Project Euler, Problem 78\n");
printf("Answer: %d\n", i);
printf("Elapsed time: %.9lf seconds\n", elapsed);
return 0;
}

189
C/p079.c Normal file
View File

@ -0,0 +1,189 @@
/* A common security method used for online banking is to ask the user for three random characters from a passcode.
* For example, if the passcode was 531278, they may ask for the 2nd, 3rd, and 5th characters; the expected reply would be: 317.
*
* The text file, keylog.txt, contains fifty successful login attempts.
*
* Given that the three characters are always asked for in order, analyse the file so as to determine the shortest possible
* secret passcode of unknown length.*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "projecteuler.h"
int compare(void *a, void *b);
int check_passcode(int **passcode, int len, int **logins, int n);
int main(int argc, char **argv)
{
int i, j, keylog, len = 4, found = 0, digits[10] = {0}, passcode_digits[10] = {0}, **passcode, **logins;
char line[5];
FILE *fp;
double elapsed;
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
if((fp = fopen("keylog.txt", "r")) == NULL)
{
fprintf(stderr, "Error while opening file %s\n", "keylog.txt");
return 1;
}
if((logins = (int **)malloc(50*sizeof(int*))) == NULL)
{
fprintf(stderr, "Error while allocating memory\n");
return 1;
}
for(i = 0; i < 50; i++)
{
if((logins[i] = (int *)malloc(3*sizeof(int))) == NULL)
{
fprintf(stderr, "Error while allocating memory\n");
return 1;
}
}
i = 0;
while(fscanf(fp, "%s", line) != EOF)
{
j = 2;
keylog = atoi(line);
while(keylog > 0)
{
logins[i][j--] = keylog % 10;
/* Check which digits are present in the login attempts.*/
digits[keylog%10]++;
keylog /= 10;
}
i++;
}
fclose(fp);
j = 0;
for(i = 0; i < 10; i++)
{
/* To generate the passcode, only use the digits present in the
* login attempts.*/
if(digits[i] > 0)
{
passcode_digits[j++] = i;
}
}
while(!found)
{
if((passcode = (int **)malloc(len*sizeof(int *))) == NULL)
{
fprintf(stderr, "Error while allocating memory\n");
return 1;
}
for(i = 0; i < len; i++)
{
if((passcode[i] = (int *)malloc(sizeof(int))) == NULL)
{
fprintf(stderr, "Error while allocating memory\n");
return 1;
}
/* For the current length, generate the first passcode with the
* digits in order.*/
*passcode[i] = passcode_digits[i];
}
/* Check if the passcode is compatible with the login attempts.*/
if(check_passcode(passcode, len, logins, 50))
{
found = 1;
break;
}
/* For the given length, check every permutation until the correct
* passcode has been found, or all the permutations have been tried.*/
while(next_permutation((void **)passcode, len, compare) != -1)
{
if(check_passcode(passcode, len, logins, 50))
{
printf("Project Euler, Problem 79\n");
printf("Answer: ");
for(i = 0; i < len; i++)
printf("%d", *passcode[i]);
printf("\n");
found = 1;
break;
}
}
for(i = 0; i < len; i++)
{
free(passcode[i]);
}
free(passcode);
/* If the passcode has not yet been found, try a longer passcode.*/
len++;
}
for(i = 0; i < 50; i++)
{
free(logins[i]);
}
free(logins);
clock_gettime(CLOCK_MONOTONIC, &end);
elapsed = (end.tv_sec - start.tv_sec) + (double)(end.tv_nsec - start.tv_nsec) / 1000000000;
printf("Elapsed time: %.9lf seconds\n", elapsed);
return 0;
}
int compare(void *a, void *b)
{
int *n1, *n2;
n1 = (int *)a;
n2 = (int *)b;
return *n1 - *n2;
}
int check_passcode(int **passcode, int len, int **logins, int n)
{
int i, j, k;
/* For every login attempt, check if all the digits appear in the
* passcode in the correct order. Return 0 if a login attempt
* incompatible with the current passcode is found.*/
for(i = 0; i < n; i++)
{
k = 0;
for(j = 0; j < len; j++)
{
if(*passcode[j] == logins[i][k])
{
k++;
if(k == 3)
{
break;
}
}
}
if(k < 3)
{
return 0;
}
}
return 1;
}

80
C/p080.c Normal file
View File

@ -0,0 +1,80 @@
/* It is well known that if the square root of a natural number is not an integer, then it is irrational.
* The decimal expansion of such square roots is infinite without any repeating pattern at all.
*
* The square root of two is 1.41421356237309504880..., and the digital sum of the first one hundred decimal digits is 475.
*
* For the first one hundred natural numbers, find the total of the digital sums of the first one hundred decimal digits
* for all the irrational square roots*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <gmp.h>
int is_square(int n);
int main(int argc, char **argv)
{
int i, j, sum = 0;
char sqrt_digits[104];
double elapsed;
struct timespec start, end;
mpf_t sqrt;
clock_gettime(CLOCK_MONOTONIC, &start);
/* Set the precision to 333 bits (should be enough for 100 decimal digits.*/
mpf_set_default_prec(333);
mpf_init(sqrt);
for(i = 2; i < 100; i++)
{
if(is_square(i))
{
continue;
}
/* Calculate the square root of the current number with the given precision
* and sum the digits to the total.*/
mpf_sqrt_ui(sqrt, i);
gmp_sprintf(sqrt_digits, "%.101Ff\n", sqrt);
sum += (sqrt_digits[0] - '0');
for(j = 2; j < 101; j++)
{
sum += (sqrt_digits[j] - '0');
}
}
mpf_clear(sqrt);
clock_gettime(CLOCK_MONOTONIC, &end);
elapsed = (end.tv_sec - start.tv_sec) + (double)(end.tv_nsec - start.tv_nsec) / 1000000000;
printf("Project Euler, Problem 80\n");
printf("Answer: %d\n", sum);
printf("Elapsed time: %.9lf seconds\n", elapsed);
return 0;
}
int is_square(int n)
{
int m;
double p;
p = sqrt(n);
m = p;
if(p == m)
{
return 1;
}
else
{
return 0;
}
}

View File

@ -785,7 +785,7 @@ int phi(int n, int *primes)
}
/* Function implementing the partition function.*/
long int partition_fn(int n, long int *partitions)
long int partition_fn(int n, long int *partitions, int mod)
{
int k, limit;
long int res = 0;
@ -800,6 +800,7 @@ long int partition_fn(int n, long int *partitions)
if(n == 0)
{
partitions[n] = 1;
return 1;
}
@ -816,12 +817,22 @@ long int partition_fn(int n, long int *partitions)
{
if(k != 0)
{
res += pow(-1, k+1) * partition_fn(n-k*(3*k-1)/2, partitions);
res += pow(-1, k+1) * partition_fn(n-k*(3*k-1)/2, partitions, mod);
}
k++;
}
partitions[n] = res;
/* Give the result modulo mod, if mod=!-1, otherwise give the full result.*/
if(mod != -1)
{
partitions[n] = res % mod;
return res;
return res % mod;
}
else
{
partitions[n] = res;
return res;
}
}

View File

@ -24,6 +24,7 @@ int pell_eq(int i, mpz_t x);
int is_semiprime(int n, int *p, int *q, int *primes);
int phi_semiprime(int n, int p, int q);
int phi(int n, int *primes);
long int partition_fn(int n, long int *partitions);
long int partition_fn(int n, long int *partitions, int mod);
int partition_fn_mpz(int n, mpz_t res, mpz_t *partitions);
#endif

50
Python/keylog.txt Normal file
View File

@ -0,0 +1,50 @@
319
680
180
690
129
620
762
689
762
318
368
710
720
710
629
168
160
689
716
731
736
729
316
729
729
710
769
290
719
680
318
389
162
289
162
718
729
319
790
680
890
362
319
760
316
729
380
319
728
716

72
Python/p077.py Normal file
View File

@ -0,0 +1,72 @@
#!/usr/bin/python
# It is possible to write ten as the sum of primes in exactly five different ways:
#
# 7 + 3
# 5 + 5
# 5 + 3 + 2
# 3 + 3 + 2 + 2
# 2 + 2 + 2 + 2 + 2
#
# What is the first value which can be written as the sum of primes in over five thousand different ways?
from timeit import default_timer
from projecteuler import is_prime
# Function using a simple recursive brute force approach
# to find all the partitions.
def count(value, n, i, target):
global primes
for j in range(i, 100):
value = value + primes[j]
if value == target:
return n + 1
elif value > target:
return n
else:
n = count(value, n, j, target)
value = value - primes[j]
return n
def main():
start = default_timer()
global primes
primes = [0] * 100
# Generate a list of the first 100 primes.
i = 0
j = 0
while j < 100:
if is_prime(i):
primes[j] = i
j = j + 1
i = i + 1
i = 2
# Use a function to count the number of prime partitions for
# each number >= 2 until the one that can be written in over
# 5000 ways is found.
while True:
n = count(0, 0, 0, i)
if n > 5000:
break
i = i + 1
end = default_timer()
print('Project Euler, Problem 77')
print('Answer: {}'.format(i))
print('Elapsed time: {:.9f} seconds'.format(end - start))
if __name__ == '__main__':
main()

41
Python/p078.py Normal file
View File

@ -0,0 +1,41 @@
#!/usr/bin/python
# Let p(n) represent the number of different ways in which n coins can be separated into piles.
# For example, five coins can be separated into piles in exactly seven different ways, so p(5)=7.
#
# OOOOO
# OOOO O
# OOO OO
# OOO O O
# OO OO O
# OO O O O
# O O O O O
#
# Find the least value of n for which p(n) is divisible by one million.
from timeit import default_timer
from projecteuler import partition_fn
def main():
start = default_timer()
N = 1000000
partitions = [0] * N
i = 0
# Using the partition function to calculate the number of partitions,
# giving the result modulo N.*/
while partition_fn(i, partitions, N) != 0:
i = i + 1
end = default_timer()
print('Project Euler, Problem 78')
print('Answer: {}'.format(i))
print('Elapsed time: {:.9f} seconds'.format(end - start))
if __name__ == '__main__':
main()

105
Python/p079.py Normal file
View File

@ -0,0 +1,105 @@
#!/usr/bin/python
# A common security method used for online banking is to ask the user for three random characters from a passcode.
# For example, if the passcode was 531278, they may ask for the 2nd, 3rd, and 5th characters; the expected reply would be: 317.
#
# The text file, keylog.txt, contains fifty successful login attempts.
#
# Given that the three characters are always asked for in order, analyse the file so as to determine the shortest possible
# secret passcode of unknown length.
from itertools import permutations
from timeit import default_timer
def check_passcode(passcode, len_, logins, n):
# For every login attempt, check if all the digits appear in the
# passcode in the correct order. Return 0 if a login attempt
# incompatible with the current passcode is found.
for i in range(n):
k = 0
for j in range(len_):
if passcode[j] == int(logins[i][k]):
k = k + 1
if k == 3:
break
if k < 3:
return 0
return 1
def main():
start = default_timer()
try:
fp = open('keylog.txt', 'r')
except:
print('Error while opening file {}'.format('keylog.txt'))
exit(1)
logins = fp.readlines()
fp.close()
digits = [0] * 10
passcode_digits = [0] * 10
for i in logins:
keylog = int(i)
# Check which digits are present in the login attempts.
while True:
digits[keylog%10] = digits[keylog%10] + 1
keylog = keylog // 10
if keylog == 0:
break
j = 0
for i in range(10):
# To generate the passcode, only use the digits present in the
# login attempts.
if digits[i] > 0:
passcode_digits[j] = i
j = j + 1
found = 0
len_ = 4
while not found:
passcode = [0] * len_
# For the current length, generate the first passcode with the
# digits in order.
for i in range(len_):
passcode[i] = passcode_digits[i]
# Check if the passcode is compatible with the login attempts.
if check_passcode(passcode, len_, logins, 50):
found = 1
break
# For the given length, check every permutation until the correct
# passcode has been found, or all the permutations have been tried.
passcodes = permutations(passcode, len_)
for i in passcodes:
if check_passcode(i, len_, logins, 50):
found = 1
res = ''.join(map(str, i))
break
# If the passcode has not yet been found, try a longer passcode.
len_ = len_ + 1
end = default_timer()
print('Project Euler, Problem 79')
print('Answer: {}'.format(res))
print('Elapsed time: {:.9f} seconds'.format(end - start))
if __name__ == '__main__':
main()

51
Python/p080.py Normal file
View File

@ -0,0 +1,51 @@
#!/usr/bin/python
# It is well known that if the square root of a natural number is not an integer, then it is irrational.
# The decimal expansion of such square roots is infinite without any repeating pattern at all.
#
# The square root of two is 1.41421356237309504880..., and the digital sum of the first one hundred decimal digits is 475.
#
# For the first one hundred natural numbers, find the total of the digital sums of the first one hundred decimal digits
# for all the irrational square roots
from mpmath import sqrt, mp
from timeit import default_timer
def is_square(n):
p = sqrt(n)
m = int(p)
if p == m:
return True
else:
return False
def main():
start = default_timer()
# Set the precision to 100 digits
mp.dps = 102
sum_ = 0
for i in range(2, 100):
if not is_square(i):
# Calculate the square root of the current number with the given precision
# and sum the digits to the total.
root = str(sqrt(i))
sum_ = sum_ + int(root[0])
for j in range(2, 101):
sum_ = sum_ + int(root[j])
end = default_timer()
print('Project Euler, Problem 80')
print('Answer: {}'.format(sum_))
print('Elapsed time: {:.9f} seconds'.format(end - start))
if __name__ == '__main__':
main()

View File

@ -399,7 +399,7 @@ def phi(n, primes):
return ph
# Function implementing the partition function.
def partition_fn(n, partitions):
def partition_fn(n, partitions, mod=-1):
# The partition function for negative numbers is 0 by definition.
if n < 0:
return 0
@ -422,8 +422,12 @@ def partition_fn(n, partitions):
res = res + pow(-1, k+1) * partition_fn(n-k*(3*k-1)//2, partitions)
k = k + 1
partitions[n] = res
return int(res)
# Give the result modulo mod, if mod!=-1, otherwise give the full result.
if mod != -1:
partitions[n] = res % mod
return res % mod
else:
partitions[n] = int(res)
return int(res)