# 3592 - Trick or Treat!

Description:

Halloween is coming soon and you've been asked to create a program to help parents and children get just what they want. Parents want to give children an upper bound on the amount of candy they can receive and children want as much candy as they get without upsetting their parents.

Fortunately, in our neighborhoods, we know in advance exactly how many pieces of candy each home hands out to the children. A child has to take all the candy given by the home so they don't seem rude, and they can't throw away or eat any candy on the way. Children also have to stop at every home in the sequence of homes.

Question:
Given these conditions write a program to find the best sequence of homes for children to visit with following input/output.

Input:
Input will be read from an ASCII text file (input.txt).  The input will consist of information about one neighborhood. The first line contains a single integer, homes, 0 < homes ≤ 10,000, that represents the maximum number of homes on the block.

The next line contains a single integer, max, 0 ≤ max ≤ 1000, representing the maximum number of pieces of candy that the child may collect. There will then be homes lines, each containing an integer, pieces, 0 ≤ pieces ≤ 1000, representing the number of pieces given at each home. Homes are numbered consecutively starting at 1.

Output:
If there is no way to select one or more consecutive homes where the sum of pieces of candy is ≤max on a single line, print “Don’t go here”. Otherwise, in the format shown below, for the sequence of homes that yield the largest number of pieces of candy ≤max, include the number of the first home to visit, the number of the last home to visit, and the sum of pieces of candy.
If there is more than one such sequence of homes, select the one with the lowest numbered first home.

Sample Input:
5
10
2
4
3
2
1

Output Corresponding to Sample Input:
Start at home 2 and go to home 5 getting 10 pieces of candy
****************************************************************************************************************************
Solution:

/*************************************************************************
** Author:      Ruiyi,Luo
** Date:        2012/01/18
** Description:
**              solve a trick or treat prolbelm that search the largest,first
**              occured sub-sequences and is also smaller than a given max.
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <intrin.h>
#define CPU_FREQUENCY 2670000000

void maxSubSequence(int *candyArray, int homes, int max)
{
int largestCandySum = -1; //  largestCandySum is the previous bigest sequence.
int largestStart = -1, largestEnd = -1;

int curSum = candyArray[0];// curSum is the current sub-sequence's sum,
int start = 0, end = 0;

bool cycle = true;

while(cycle)
{
if(curSum > largestCandySum && curSum <= max)
{
largestCandySum = curSum;
largestStart = start;
largestEnd = end;

//End the unnecessary calculation when exactly a max is found.
if(largestCandySum == max)
{
cycle = false;continue;
}
}

//			printf("curSum: %d  start: %d end: %d\n",curSum,start,end);
if((end == homes - 1 && curSum <= max)|| (start == homes - 1 && end == homes - 1)) cycle  = false;

if(curSum > max)
{
++start;
if(start > end)
{
end ++;
curSum = candyArray[start];
}else
curSum -= candyArray[start-1];
}
else
{
curSum += candyArray[++end];
}

}

if(largestCandySum == -1) printf("Don't go here\n");
else
printf("Start at home %d and go to home %d getting %d pieces of candy\n",largestStart + 1, largestEnd + 1,largestCandySum);
}

int main(int argc, char *argv[])
{

FILE *input;
if((input = fopen("input.txt","r")))
{
int homes = 0, max = 0;
fscanf(input,"%d",&homes);
fscanf(input,"%d",&max);

int *candyArray = NULL; // contains candy pieces given at each home

if((candyArray = (int *)malloc(homes*sizeof(int))) == NULL)
{
printf("memory allocation failed, exit\n");
exit(1);
}

for(int i = 0; i < homes; i++)
{
fscanf(input,"%d",&candyArray[i]);
}

maxSubSequence(candyArray,homes,max);

fclose(input);
free(candyArray);
system("pause");
}else
printf("File open error");
return 0;

}

***********************************************************************************************************************
Subsidiary question:
If you are familiar with OpenMP:
Parallelize the program with OpenMP for multi-core execution.

/*************************************************************************
** Author:      Ruiyi,Luo
** Date:        2012/01/18
** Description:
**              solve a trick or treat prolbelm that search the largest,first
**              occured sub-sequences and is also smaller than a given max.
****************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include <omp.h>
#include<memory.h>
#include <windows.h>  // #include <unistd.h> on linux. system("pause");
//define DEBUG

void maxSubSequence(int *candyArray, int homes, int max)
{
#pragma omp parallel
{
}
// Reduce threads when homes < setting ones.
{
}

int *subLargestSum   = (int  *)malloc(num_threads * sizeof(int));/// Record the sub largest each sub sequences.
int *sublargestStart = (int  *)malloc(num_threads * sizeof(int));/// Record the bigest sequence.for each thread.
int *sublargestEnd   = (int  *)malloc(num_threads * sizeof(int));/// Record the biggest sequence's start.
bool *finish         = (bool *)malloc(num_threads * sizeof(bool));

for(int i = 0; i < num_threads; i++) subLargestSum[i] = -1;
int sublength = (homes + num_threads - 1) / num_threads;/// Each thread process a sublength size sequence.

#pragma omp parallel
{

int start = sublength * thread_idx, end = start;

#ifdef DEBUG
#endif

int nextSubSequencePos = start + sublength;///current thread process interval:[start,nextSubSequencePos]

bool cycle = finish[thread_idx];//needless: #pragma omp atomic

while(cycle)
{
if(curSum > subLargestSum[thread_idx] && curSum <= max)
{

// If  exactly a equal to max sub-sequence is found, more loops and calculation is unnecessary.
// Also for the threads with idex subsequent.
{
{
finish[i] = false;	//needless: #pragma omp atomic. loop more will not affect the result.
}
cycle = false;
continue;
}
}

#ifdef DEBUG
Sleep(100); // For a complete output
#endif

{
// The thread with the last index terminated
if((end == homes - 1 && curSum <= max)|| (start == homes - 1 && end == homes - 1))
{
cycle = false;
}
}else
{
// Threads except the last one terminates when the start execeed its intervial.
// Note that thread with index ahead may process the intervial behind it if max is large enough.
if(start == nextSubSequencePos - 1 || (end == homes - 1 && curSum <= max)|| (start == homes - 1 && end == homes - 1))
{
finish[thread_idx] = false; //needless: #pragma omp atomic
cycle = false;
}
}

if(curSum > max)
{
++start;
if(start > end)
{
end ++;
curSum = candyArray[start];
}else
curSum -= candyArray[start-1];
}
else
{
curSum += candyArray[++end];
}

// cycle update value, eliminated the unnecessary loop
cycle = finish[thread_idx]; //needless: #pragma omp atomic

}
}//end parallel

//search the largest sub-sequences in records recorded by each thread.
int largestSum = -1,idx = -1;
for(int i = 0; i < num_threads; i++)
{
if(largestSum < subLargestSum[i])
{
largestSum = subLargestSum[i];
idx = i;
}
}

if(largestSum == -1) printf("Don't go here\n");
else
printf("Start at home %d and go to home %d getting %d pieces of candy\n",sublargestStart[idx] + 1, sublargestEnd[idx] + 1,largestSum);
}

int main(int argc, char *argv[])
{

FILE *input;
if((input = fopen("input.txt","r")))
{

int homes = 0, max = 0;
fscanf(input,"%d",&homes);
fscanf(input,"%d",&max);

int *candyArray = NULL; // contains candy pieces given at each home
if((candyArray = (int *)malloc(homes*sizeof(int))) == NULL)
{
printf("memory allocation failed, exit\n");
exit(1);
}

for(int i = 0; i < homes; i++)
{
fscanf(input,"%d",&candyArray[i]);
}

//	_int64 start_t = __rdtsc();
maxSubSequence(candyArray,homes,max);
//	_int64 timeUsed = __rdtsc() - start_t;
//	printf(" %.4f(s)\n", (double)timeUsed/(double)CPU_FREQUENCY);

fclose(input);
free(candyArray);

system("pause");
}else
printf("File open error");
return 0;

}


************************************************************************************************************

Instruction

#### 1. An o(n) solution of trick or treat!

I have managed to finish this task in linger time o(n) and minimum spaces other than a violence search algorithm with o(n2) times and o(n) spaces. It just need to maintain three variable to record the largest candy sequence and three local variables used for current loop.

A Brief Flowchart:

Figure 1. maxSubSequence function's brief flowchart

Note that it's a brief flowchart. You can see much more clear in the code, such as (1) in figure 1, when exactly a max is found, more loops and calculation is unnecessary.

(3) in figure 1, think about a candy sequence(2,3,4,5) but the max is 1 and whenstart++,it's possible start > end. Here is need to assigned the value in start pos tocurSum and then,end++.

#### 2. Parallelization using OpenMP.

Parallelizing loops that an advantage of OpenMP can't be used here because it has dependency relationship between each loops and it worth it. Accuracy to say, the current cycle's result depends on the value of variablestart, end, largestCandySumcurSum assigned in previous cycle.

In this parallelization, each thread will process a sub-array of thecandyArray.

The flowchart as follows:

Each thread process a homes/num_threads length interval sequence: [(homes/num_threads)*thread_idx,homes/num_threads)*(thread_idx+1)]. Termination condition (1) in figure 2. is nearly the same as the one in section 1 except that when start > the upper of the interval, the loop will be terminated.That's to say, the thread with index 0 will process wholecandyArray ifmax is large enough. Termination condition (2) is the same as section 1 and it is only belong to the thread with last index.

A simply demo:

It's powerful at the condition that when the max-sub-sequence locates at the tail of thecandyArray. however when the max is big enough, the performance will be equal to the single core as it is calculated by the thread with index = 0.

Threads number set like this：set OMP_NUM_THREADS=4 in shell, or omp_set_num_threads(4) in function. Through my test, however, there is no advantage comparing with single thread algorithm under the condition 0 < homes ≤ 10,000, as workload is too small and the single one can run at o(n) time.

03-23 44

11-01 507

03-28 38

12-18 129

04-29 307

02-10 184

08-28 1509

05-02 792

02-20 137

11-05 898