关闭

3592 - Trick or Treat!

908人阅读 评论(0) 收藏 举报

该题目是年前面试英伟达(NVIDIA)时候的前奏,NV额外要求开多线程, 搜索后发现是道ACM 题目:North America - Southeast - 2006/2007。

可惜我写的并没有被Accept,附上代码和最后的文档说明,有高手可以帮我看看。

附上提交地址:http://livearchive.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=18&page=show_problem&problem=1593

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) 
// each thread process a sub-sequence [start,nextSubSequencePos],thread with index ahead may process the intervial behind it.
{  
	int num_threads = 0;
#pragma omp parallel
	{
		num_threads = omp_get_num_threads();
	}
	// Reduce threads when homes < setting ones.
	if(num_threads > homes) 
	{
		omp_set_num_threads(homes);
		num_threads = homes;
	}

	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));
	
	memset(finish,true,num_threads);
	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 thread_idx = omp_get_thread_num();
		subLargestSum[thread_idx]   = -1; 
		sublargestStart[thread_idx] = -1;
		sublargestEnd[thread_idx]   = -1;

		int start = sublength * thread_idx, end = start;

#ifdef DEBUG
		printf("thread_idx:%d start: %d\n",thread_idx,start);
#endif

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

		int curSum = candyArray[thread_idx];

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

		while(cycle)
		{         
			if(curSum > subLargestSum[thread_idx] && curSum <= max)
			{
				subLargestSum[thread_idx] = curSum;
				sublargestStart[thread_idx] = start;
				sublargestEnd[thread_idx] = end;
			
				// If  exactly a equal to max sub-sequence is found, more loops and calculation is unnecessary.
				// Also for the threads with idex subsequent.
 				if(subLargestSum[thread_idx] == max)
				{
					for(int i = thread_idx;i<num_threads;i++)
					{
						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
			printf("thread_id: %d  curSum: %d  start: %d end: %d\n",thread_idx, curSum,start,end);
#endif

 
			if(thread_idx == num_threads - 1)
			{
				// The thread with the last index terminated  
				if((end == homes - 1 && curSum <= max)|| (start == homes - 1 && end == homes - 1)) 				
				{
					finish[thread_idx] = false;
					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")))
	{
		omp_set_num_threads(4); // setting threads number.

		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:

 

Figure 2. multi-threads

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.

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:48354次
    • 积分:468
    • 等级:
    • 排名:千里之外
    • 原创:7篇
    • 转载:5篇
    • 译文:1篇
    • 评论:17条
    文章分类
    最新评论
    Android开发
    全心投入Android开发