Skip to content

Commit

Permalink
Merge pull request #27 from tomasalmeida/reto/tomasalmeida_using_c
Browse files Browse the repository at this point in the history
Solution single thread in C
  • Loading branch information
tomasalmeida committed Jun 7, 2017
2 parents 6b9ebd5 + d47d7b6 commit 8b11d69
Show file tree
Hide file tree
Showing 6 changed files with 382 additions and 0 deletions.
1 change: 1 addition & 0 deletions 201705/tomas.almeida/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
reto
69 changes: 69 additions & 0 deletions 201705/tomas.almeida/README.md
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
9 changes: 9 additions & 0 deletions 201705/tomas.almeida/inputGenerator.py
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(',','')
208 changes: 208 additions & 0 deletions 201705/tomas.almeida/reto.c
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;
}
}
Loading

0 comments on commit 8b11d69

Please sign in to comment.