转载请注明出处:http://blog.csdn.net/u012860063
题目链接:http://poj.org/problem?id=1011
Description
Input
Output
Sample Input
9 5 2 1 5 2 1 5 2 1 4 1 2 3 4 0
Sample Output
6 5
Source
题目的大意:是给了你有限个棍子以及每个棍子的长度,而且所有的棍子都是由有限个长度相同的棍子截断得到的,让你求被截棍子的最小长度,本题的算法是深搜,当然需要几个剪枝的!
代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
int sticks[65];
int used[65];
int n,len;
bool dfs(int i,int l,int t)//i为当前试取的棍子序号,l为要拼成一根完整的棍子还需要的长度,t初值为所有棍子总长度 
{
    if(l==0)
    {
        t -= len;//如果len为所有棍子的和
        if(t == 0)
			return true;       
        for(i = 0; used[i]; i++);            //剪枝1:搜索下一根大棍子的时候,找到第一个还没有使用的小棍子开始        
		used[i]=1;                           //由于排序过,找到的第一根肯定最长,也肯定要使用,所以从下一根开始搜索
        if(dfs(i+1,len-sticks[i],t))
			return true;
        used[i]=0;//回溯
        t+=len;
    }
    else
    {
        for(int j = i; j < n; j++)
        {
            if(j>0 && (sticks[j]==sticks[j-1]&&!used[j-1]))  //剪枝2:前后两根长度相等时,如果前面那根没被使用,也就是由前面那根
                continue;                                                //开始搜索不到正确结果,那么再从这根开始也肯定搜索不出正确结果,此剪枝威力较大			
            if(!used[j] && l>=sticks[j])   //剪枝3:最简单的剪枝,要拼成一根大棍子还需要的长度L>=当前小棍子长度,才能选用                           
            {
                l-=sticks[j];
                used[j]=1;
                if(dfs(j,l,t))
					return true;				
                l+=sticks[j];//回溯
                used[j]=0;                
                if(sticks[j]==l)    //剪枝4:威力巨大的剪枝,程序要运行到此处说明往下的搜索失败,若本次的小棍长度刚好填满剩下长度,但是后
                    break;           //面的搜索失败,则应该返回上一层
            }
        }
    }
    return false;
}
bool cmp(const int a, const int b)
{ 
    return a>b; 
}
int main()
{
    while(cin>>n&&n)
    {
        int sum=0;int max = -1;
        for(int i = 0; i < n; i++)
        {
            cin>>sticks[i];
            sum += sticks[i];
            used[i] = 0;
			if(sticks[i] > max)//找出最长的棍子
				max = sticks[i];
        }
        
        sort(sticks,sticks+n,cmp);   //剪枝5:从大到小排序后可大大减少递归次数
        
        bool flag=false;
        for(len = max; len <= sum/2; len++)   //剪枝6:大棍长度一定是所有小棍长度之和的因数,且最小因数应该不小于小棍中最长的长度
        {
            if(sum%len == 0)     
            {
                if(dfs(0,len,sum))
                {
                    flag=true;
                    cout<<len<<endl;
                    break;
                }
            }
        }
        if(!flag)
            cout<<sum<<endl;
    }
    return 0;
}poj1011 Sticks DFS+回溯,布布扣,bubuko.com
原文:http://blog.csdn.net/u012860063/article/details/34948659