Home > Enterprise >  Optimization of obvious task
Optimization of obvious task

Time:03-01

My task is very simple, but the most obvious solution is too slow.

I have a massive of positive elements and some questions connected with this massive. I have to find the longest segment (l,r) (with given l) with the sum of the elements less than given S. My code should be in the C language, I have tried to find that (l,r) segment with trivial for or while (just starting cycle for l element and going farther while sum is less then S, but it's too slow). My teacher recommended me to count all sums from 0 to i and use this sums to find needed segment (l,r), but I really have no idea how to make it. Example of test:

10 7
1
4
0
5
6
0
0
1
5
3
0 100
0 5
4 11
4 12
4 13
10 100

First number N (10) is the number of elements in massive
Second number K (7) is the number of tests
Next 10 numbers (1,4,0,5,6,0,0,1,5,3) are elements of array
Last 7 pairs of elements are tests (first number is l and second is sum)
And the anwsers are

10
3
8
9
9
10
8

My code

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

uint32_t Query (uint32_t l, uint64_t sum,const uint32_t *arr,uint32_t n);


int main() {;
    FILE *f = fopen("input.txt","r");
    FILE *s = fopen("output.txt","w");
    uint32_t n,t,l;
    uint64_t sum;
    fscanf(f,"%d",&n);
    fscanf(f,"%d",&t);
    uint32_t *arr = malloc(sizeof (uint32_t) * n);
    for( int i = 0; i < n; i  ){
        fscanf(f,"%d",&arr[i]);
    }
    for( int i = 0; i < t; i  ){
        fscanf(f,"%d %lld",&l,&sum);
        Query(l,sum,arr,n);
    }
    return 0;
}

uint32_t Query (uint32_t l, uint64_t sum,const uint32_t *arr,uint32_t n){
    uint64_t summy = 0;
    uint32_t  i;
    for( i = l ; i < n; i  ){
        summy = arr[i];
        if (summy > sum){
            return i;
        }
    }
    return i;
}

CodePudding user response:

For speed; if you know the sum of the segment (l, r), then you can determine the sum of the segment (l 1, r 1) by subtracting the entry at array[l] and adding the entry at array[r 1].

Therefore (untested):

void FindHighestSum (const uint32_t *array, uint32_t arraySize, uint32_t segmentSize) {
    uint32_t bestSumPos;
    uint64_t bestSum;
    uint32_t r;
    uint32_t l;
    uint64_t sum = 0;

    if(arraySize < segmentSize) {
        printf("Error: Array too small for segment size\n");
        return;
    }

    // Find sum of first segment

    for(r = 0; r < segmentSize; r  ) {
        sum  = array[r];
    }

    // Sum of first segment is the largest sum so far

    bestSumPos = 0;
    bestSum = sum;

    // Find largest sum of all segments

    for(l = 1; l < arraySize - segmentSize; l  ) {
        sum = sum - array[l]   array[r];
        r  ;

        if(sum > bestSum) {
            // Found a new largest sum
            bestSumPos = l;
            bestSum = sum;
        }
    }
    printf("Highest sum from %" PRIu32 " to %" PRIu32 " (sum is %" PRIu64 ")\n", bestSumPos, bestSumPos   segmentSize - 1, bestSum);
}

CodePudding user response:

I think what your teacher meant, was, instead of storing x[i] = a[i]:

for( int i = 0; i < n; i  ){
    fscanf(f,"%d",&arr[i]);
}

you could the running sum x[i] = \sum_{n=0}^{i} x[n], this is the analog of storing the integral:

int energy = 0;
for( int i = 0; i < n; i  ) {
    int value;
    if(fscanf(f,"%d",&value) != 1) exit(EXIT_FAILURE);
    energy  = value;
    arr[i] = energy;
}

Because the problem is linear, this allows you to look at only the endpoints. Thus, you can reduce your search incrementing at every step, O(n), and use a binary search, O(log n). Specifically, you will need to take the upper bound; there is no standard way of doing this in C, so you will have to write your own from bsearch and upper bound.

  • Related