129 lines
3.0 KiB
C

/* A permutation is an ordered arrangement of objects. For example, 3124 is one possible permutation of the digits 1, 2, 3 and 4.
* If all of the permutations are listed numerically or alphabetically, we call it lexicographic order. The lexicographic permutations of 0, 1 and 2 are:
*
* 012 021 102 120 201 210
*
* What is the millionth lexicographic permutation of the digits 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9?*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "projecteuler.h"
void next_perm(int **perm, int n);
void swap(int **vet, int i, int j);
int compare(void *a, void *b);
int main(int argc, char **argv)
{
int i, res[10];
int **perm;
double elapsed;
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
if((perm = (int **)malloc(10*sizeof(int *))) == NULL)
{
fprintf(stderr, "Error while allocating memory\n");
return 1;
}
for(i = 0; i < 10; i++)
{
if((perm[i] = (int *)malloc(sizeof(int))) == NULL)
{
fprintf(stderr, "Error while allocating memory\n");
return 1;
}
*perm[i] = i;
}
for(i = 0; i < 999999; i++)
{
/* Function that generates permutations in lexicographic order.
* Finish when the 1000000th is found.*/
next_perm(perm, 10);
}
for(i = 0; i < 10; i++)
{
res[i] = *perm[i];
free(perm[i]);
}
free(perm);
clock_gettime(CLOCK_MONOTONIC, &end);
printf("Project Euler, Problem 24\n");
printf("Answer: ");
for(i = 0; i < 10; i++)
{
printf("%d", res[i]);
}
printf("\n");
elapsed = (end.tv_sec - start.tv_sec) + (double)(end.tv_nsec - start.tv_nsec) / 1000000000;
printf("Elapsed time: %.9lf seconds\n", elapsed);
return 0;
}
void swap(int **vet, int i, int j)
{
int *tmp;
tmp = vet[i];
vet[i] = vet[j];
vet[j] = tmp;
}
int compare(void *a, void *b)
{
int *n1, *n2;
n1 = (int *)a;
n2 = (int *)b;
return *n1 - *n2;
}
/* Implements SEPA (Simple, Efficient Permutation Algorithm)
* to find the next permutation.*/
void next_perm(int **perm, int n)
{
int i, key;
/* Starting from the right of the array, for each pair of values
* if the left one is smaller than the right, that value is the key.*/
for(i = n - 2; i >= 0; i--)
{
if(compare((void *)perm[i], (void *)perm[i+1]) < 0)
{
key = i;
break;
}
}
/* If no left value is smaller than its right value, the
* array is in reverse order, i.e. it's the last permutation.*/
if(i == -1)
{
return;
}
/* Find the smallest value on the right of the key which is bigger than the key itself,
* considering that the values at the right of the key are in reverse order.*/
for(i = key + 1; i < n && compare((void *)perm[i], (void *)perm[key]) > 0; i++);
/* Swap the value found and the key.*/
swap(perm, key, i-1);
/* Sort the values at the right of the key. This is
* the next permutation.*/
insertion_sort((void **)perm, key+1, n-1, compare);
}