POJ1011 HDU1455 Sticks

DFS的好题, 需要深度的剪枝, 详细请看注释


/*******************************************************************************
 # Author : Neo Fung
 # Email : [email protected]
 # Last modified: 2012-03-08 20:31
 # Filename: POJ1011 HDU1455 Sticks.cpp
 # Description : 
 ******************************************************************************/
#ifdef _MSC_VER
#define DEBUG
#define _CRT_SECURE_NO_DEPRECATE
#endif

#include <fstream>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <string>
#include <limits.h>
#include <algorithm>
#include <math.h>
#include <numeric>
#include <functional>
#include <ctype.h>
#define MAX 70
using namespace std;

int array[MAX];
bool used[MAX];

bool dfs(const int &x, const int &n, const int &total,const int &remain, const int &left)
// x为上一条使用的小棍子, n为总的小棍子数, total为需要拼成的长棍子长度, 
// remain为离拼好一条的长棍子的长度, left为还需要拼好的长棍子数
{
	if(left<2)  //剪枝, 如果只剩下一条长棍子还没拼, 则可以知道余下的小棍子肯定可以拼成这条长棍子的
		return true;

  used[x]=true;

  bool ans=false;
	for(int i=0;i<n && !ans;++i)
		if(!used[i])
	{
		if(i>0 && !used[i-1] && array[i]==array[i-1])
    // 剪枝, 如果上一条小棍子和本条小棍子一样长, 且上一条小棍子用了也失败, 则可知这条小棍子也同样失败
			continue;

		if(remain<array[i]) //剪枝,小棍子比离拼好一条长棍子的长度大
			continue;

		else if(remain==array[i]) // 如果第i条棍子刚好可以拼好一条长棍子, 则left--, remain重置为total
			ans = dfs(i,n,total,total,left-1);

		else if(remain>array[i])  // 如果第i条加上去后还差一点, 继续拼
			ans = dfs(i,n,total,remain-array[i],left);

    if(remain ==total && !ans)  
    // 剪枝, 如果现在需要拼成的长棍子一点都还没有完成(remain==total),
    // 而且, 余下小棍子里最长的也不足以完成任务, 则余下的小棍子也不足以完成
    {
      used[x]=false;
      return false;
    }
	}

  used[x]=false;
	return ans;
}

int main(void)
{
#ifdef DEBUG  
  freopen("../stdin.txt","r",stdin);
  freopen("../stdout.txt","w",stdout); 
#endif  

	int n;

	while(scanf("%d",&n) && n)
	{
		int max_len=INT_MIN,sum=0;
    memset(used,false,sizeof(used));
		for(int i=0;i<n;++i)
		{
			scanf("%d",&array[i]);
			sum+=array[i];
			max_len=max(max_len,array[i]);
		}

    sort(array,array+n,greater<int>());

		int ans=max_len;
		for(;ans<=sum/2;++ans)  //剪枝, 需要拼成的长棍子的长度范围应该是[max_len,sum/2]
			if(!(sum%ans))  // 剪枝, 只有总长度是长棍子长度的整数倍才有效
			{
				if(dfs(n,n,ans,ans,sum/ans))
				{
					printf("%d\n",ans);
					break;
				}
			}
		if(ans>sum/2)
			printf("%d\n",sum);
	}

  return 0;
}


你可能感兴趣的:(POJ1011 HDU1455 Sticks)