3592 - Trick or Treat!

原创 2012年03月24日 11:42:54

该题目是年前面试英伟达(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.

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

洛谷P2921/BZOJ1589[USACO08DEC]在农场万圣节Trick or Treat on the Farm

题目描述 Every year in Wisconsin the cows celebrate the USA autumn holiday of Halloween by dressing...

HDU4071Trick or Treat(三分查找)

题意:在一个直角坐标系中,给出n个点。在 x 轴上选一个点,使得到那 n 个点的最长距离最短。思路:用三分查找枚举即可。控制精度。

BNU 4260 Trick or Treat && ZOJ 3386 (三分查找)

代码: #include using namespace std; const double eps=1e-7; const double inf=0x3f3f3f3f; const int N=5...

HDU4071 Trick or Treat 二分

Problem Address:http://acm.hdu.edu.cn/showproblem.php?pid=4071   【思路】   二分答案。 假想所有点被一个圆包围着,那么题目...

BNUoj 4260 Trick or Treat (三分)

题目链接:http://www.bnuoj.com/v3/problem_show.php?pid=4260 题目大意:给你n个点的坐标,求在x轴上一点x,使得它到所有点的最大距离最小,并输出最大距...

Trick or Treat

 Johnny and his friends have decided to spend Halloween night doing the usual candy collection fr...

POJ3873 Trick or Treat

题目链接:http://poj.org/problem?id=3873 题目描述: 这题

Treat 算法论文 英文

  • 2017-09-26 16:25
  • 835KB
  • 下载

【CodeVS 1222】信与信封的问题 随机化+treat Hungery

题目nn封信依次编号为11到nn,nn个信封也依次编号为11到nn. Small John能提供一组信息:第ii封信肯定不是装在信封jj中. 请编程帮助Small John,确定一定匹配的信和信封...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)