-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #27 from tomasalmeida/reto/tomasalmeida_using_c
Solution single thread in C
- Loading branch information
Showing
6 changed files
with
382 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
reto |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
# Second @vigojug challenge by @tomasalmeida | ||
|
||
* You should have GCC to compile this :-) | ||
* You should have python to generate some big arrays | ||
|
||
I am using this PC for tests | ||
|
||
``` | ||
$ cat /proc/cpuinfo | ||
processor : 0 | ||
vendor_id : GenuineIntel | ||
cpu family : 6 | ||
model : 37 | ||
model name : Intel(R) Core(TM) i5 CPU M 430 @ 2.27GHz | ||
stepping : 2 | ||
microcode : 0xe | ||
cpu MHz : 1330.000 | ||
``` | ||
|
||
The solutions is **mono thread** so more cpu's do not help. | ||
|
||
## Compile | ||
|
||
`$ gcc -g -O3 -o reto reto.c` | ||
|
||
* `gcc` is the compiler (yes, we need to compile, soooo old) | ||
* `-g` is for debugging purposes | ||
* `-O3` is for GCC optimizations (it changes A LOT) | ||
* `-o` for the name of the executable file | ||
|
||
## Tests generation | ||
|
||
I am using python to generate the arrays, I am not a good python programmer, so take the script without any warranty :D | ||
|
||
`$ ./inputGenerator.py RANGE_BEGIN RANGE_END ELEMENTS` | ||
|
||
Example: | ||
|
||
``` | ||
$ ./inputGenerator.py -10 10 5 | ||
9 5 -3 -2 -10 | ||
``` | ||
### Tests | ||
``` | ||
$ time ./reto `./inputGenerator.py -10000 10000 3000` | ||
Wow let's have fun with 3000 elements | ||
6 -4 10160811 -9824338 | ||
Element[ 0] = -9997 | Subsets = 1 | ||
Element[ 1] = -9995 | Subsets = 2 | ||
... | ||
... | ||
Element[ 1969] = -4 | Subsets = 9824304 | ||
Element[ 1970] = 6 | Subsets = 9824318 | ||
Element[ 1971] = 9 | Subsets = 9824327 | ||
There is a subset with sum 0!!! | ||
real 0m45.268s | ||
user 0m45.012s | ||
sys 0m0.184s | ||
``` | ||
You can play with the generator to give you more bad results :-) | ||
|
||
Also, there is a `tester.sh` to perform quick tests. | ||
|
||
# License: | ||
GPL 3.0 | ||
|
||
keep it free as in freedom |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#!/usr/bin/env python | ||
|
||
import random | ||
import sys | ||
|
||
floor = int(sys.argv[1]) | ||
ceil = int(sys.argv[2]) | ||
number = int(sys.argv[3]) | ||
print str(random.sample(range(floor, ceil),number))[1:-1].replace(',','') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <limits.h> | ||
|
||
#define kBUFFERSIZE 4096 // How many bytes to read at a time | ||
|
||
#define SOLUTION_NOT_FOUND 0 | ||
#define SOLUTION_FOUND 1 | ||
#define SOLUTION_IMPOSSIBLE 2 | ||
|
||
//copied from here http://www.comp.dit.ie/rlawlor/Alg_DS/sorting/quickSort.c | ||
int partition( int a[], int l, int r) { | ||
int pivot, i, j, t; | ||
pivot = a[l]; | ||
i = l; j = r+1; | ||
while( 1) | ||
{ | ||
do ++i; while( a[i] <= pivot && i <= r ); | ||
do --j; while( a[j] > pivot ); | ||
if( i >= j ) break; | ||
t = a[i]; a[i] = a[j]; a[j] = t; | ||
} | ||
t = a[l]; a[l] = a[j]; a[j] = t; | ||
return j; | ||
} | ||
|
||
//copied from here http://www.comp.dit.ie/rlawlor/Alg_DS/sorting/quickSort.c | ||
void quickSort( int a[], int l, int r) | ||
{ | ||
int j; | ||
if( l < r ) | ||
{ | ||
// divide and conquer | ||
j = partition( a, l, r); | ||
quickSort( a, l, j-1); | ||
quickSort( a, j+1, r); | ||
} | ||
|
||
} | ||
|
||
//convert input and get some special values | ||
int atoiAndFindElements( int inputSize, | ||
char** input, | ||
int* closeToZeroPositive, | ||
int* closetoZeroNegative, | ||
long* sumPositiveNumbers, | ||
long* sumNegativeNumbers, | ||
int* sortedInputList[]) { | ||
for(int i = 0; i < inputSize; i++) { | ||
int number = atoi(input[i]); | ||
if ( number == 0) { | ||
return 0; | ||
} | ||
if (number > 0 ) { | ||
*closeToZeroPositive = (number < *closeToZeroPositive ? number : *closeToZeroPositive); | ||
*sumPositiveNumbers += number; | ||
} else { | ||
*closetoZeroNegative = (number > *closetoZeroNegative ? number : *closetoZeroNegative); | ||
*sumNegativeNumbers += number; | ||
} | ||
(*sortedInputList)[i] = number; | ||
} | ||
return 1; | ||
} | ||
|
||
int main( int argc, char** argv ) { | ||
int currentState = SOLUTION_NOT_FOUND; | ||
|
||
int inputSize = argc-1; | ||
printf("Wow let's have fun with %d elements\n", inputSize); | ||
|
||
int* sortedInputList = (int*) malloc((inputSize)*sizeof(int)); | ||
|
||
int closeToZeroPositive = INT_MAX; | ||
int closetoZeroNegative = INT_MIN; | ||
long sumPositiveNumbers = 0; | ||
long sumNegativeNumbers = 0; | ||
|
||
int foundZero = atoiAndFindElements(inputSize, | ||
&(argv[1]), | ||
&closeToZeroPositive, | ||
&closetoZeroNegative, | ||
&sumPositiveNumbers, | ||
&sumNegativeNumbers, | ||
&sortedInputList); | ||
|
||
printf("%10ld %8d %8d %10ld\n", sumNegativeNumbers, closetoZeroNegative, closeToZeroPositive, sumPositiveNumbers); | ||
|
||
// if has zero return eureka! | ||
if(foundZero == 0) { | ||
currentState = SOLUTION_FOUND; | ||
} | ||
|
||
// OPTIMIZATION: dummy cases the small element of each side is already bigger than the sum of the other side | ||
if (currentState == SOLUTION_NOT_FOUND && | ||
(sumPositiveNumbers + closetoZeroNegative < 0 || | ||
sumNegativeNumbers + closeToZeroPositive > 0)) { | ||
//impossible solution | ||
currentState = SOLUTION_IMPOSSIBLE; | ||
} | ||
|
||
// now we can have some fun :) | ||
|
||
//sort the monster to apply some tricks | ||
quickSort(sortedInputList, 0, inputSize-1); | ||
|
||
int listSize = (-1*sumNegativeNumbers) + 1; | ||
//store partial sums (max is the sumNegativeNumbers until zero) | ||
long* preliminarSumsArray = (long*) malloc(listSize*sizeof(long)); | ||
//store only negative sums (max is the sumNegativeNumbers until zero) | ||
char* listOfExistentNegativeSums = (char*) calloc(listSize,sizeof(char)); | ||
|
||
//store only positive sums | ||
int positiveListSize = sumPositiveNumbers > -sumNegativeNumbers ? sumPositiveNumbers : -sumNegativeNumbers; | ||
printf("List size is %d \n", positiveListSize); | ||
char* listOfExistentPositiveSums = (char*) calloc(positiveListSize+1,sizeof(char)); | ||
|
||
//find first positive element using binary search | ||
int first = 0; | ||
int last = inputSize - 1; | ||
int firstPositivePosition = (first+last)/2; | ||
while (first <= last) { | ||
if (sortedInputList[firstPositivePosition] < closeToZeroPositive) { | ||
first = firstPositivePosition + 1; | ||
} else if (sortedInputList[firstPositivePosition] == closeToZeroPositive) { | ||
break; | ||
} else { | ||
last = firstPositivePosition - 1; | ||
} | ||
firstPositivePosition = (first + last)/2; | ||
} | ||
for(int j=firstPositivePosition; j < inputSize; j++) { | ||
printf("Set to 1 = %d \n", sortedInputList[j]); | ||
listOfExistentPositiveSums[sortedInputList[j]] = 1; | ||
} | ||
|
||
//OPTIMIZATION: add zero to create the case of the element alone | ||
preliminarSumsArray[0] = 0; | ||
long firstPositionFree = 1; | ||
long numberOfPreliminarSums = 1; | ||
for (int i = 0; i < inputSize && currentState == SOLUTION_NOT_FOUND; i++) { | ||
int currentNumber = sortedInputList[i]; | ||
printf("Element[%6d] = %8d | Subsets = %12lu \n", i, currentNumber, numberOfPreliminarSums); | ||
|
||
if (currentNumber > 0) { | ||
//OPTIMIZATION: if the currentNumber + negativeSUM is greater than zero | ||
// we cannot generate a zero sum, so we can stop | ||
if (currentNumber + sumNegativeNumbers > 0) { | ||
currentState = SOLUTION_IMPOSSIBLE; | ||
continue; | ||
} | ||
|
||
//OPTIMIZATION: if currentNumber is positive and its sum was done, so we found a solution | ||
if (listOfExistentNegativeSums[currentNumber] == 1) { | ||
currentState = SOLUTION_FOUND; | ||
continue; | ||
} | ||
} | ||
|
||
|
||
for(long currentPosition = 0; | ||
currentPosition < numberOfPreliminarSums && currentState == SOLUTION_NOT_FOUND; | ||
currentPosition++) { | ||
long sum = preliminarSumsArray[currentPosition] + currentNumber; | ||
if (sum == 0 ) { | ||
currentState = SOLUTION_FOUND; | ||
} else if (currentNumber < 0 && listOfExistentPositiveSums[-sum] == 1) { | ||
currentState = SOLUTION_FOUND; | ||
} else { | ||
//printf("%ld %d %d %d %d \n", sum, (sum < 0), (sum + currentNumber <= 0), (sum + sumPositiveNumbers >= 0), (listOfExistentNegativeSums[-sum])); | ||
//OPTIMIZATION: positive sums are useless | ||
if ((sum < 0) && | ||
//OPTIMIZATION: the list is sorted, if the next sum is greater than zero, sum is useless | ||
(sum + currentNumber <= 0) && | ||
//OPTIMIZATION: I need to be able to generate a possible positive sum | ||
(sum + sumPositiveNumbers >= 0) && | ||
//OPTIMIZATION: the sum does not exist in my list | ||
(listOfExistentNegativeSums[-sum] == 0)) { | ||
//sum is useful, storing it | ||
preliminarSumsArray[firstPositionFree++] = sum; | ||
listOfExistentNegativeSums[-sum] = 1; | ||
} | ||
} | ||
} | ||
numberOfPreliminarSums = firstPositionFree; | ||
// for (int j = 0 ; j < firstPositionFree; j++){ | ||
// printf(" %ld ", preliminarSumsArray[j]); | ||
// } | ||
// printf("\n"); | ||
} | ||
|
||
//a good man always frees the used memory | ||
free(listOfExistentNegativeSums); | ||
free(listOfExistentPositiveSums); | ||
free(preliminarSumsArray); | ||
free(sortedInputList); | ||
|
||
switch (currentState) { | ||
case SOLUTION_NOT_FOUND: | ||
case SOLUTION_IMPOSSIBLE: | ||
printf("\n> > > There is NO possible solutions :-(\n"); | ||
return 1; | ||
case SOLUTION_FOUND: | ||
default: | ||
printf("\n> > > There is a subset with sum Zero :-)\n"); | ||
return 0; | ||
} | ||
} |
Oops, something went wrong.