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
此题一共有4种剪枝方案:
1、之前的一根棍子安装失败,之后不尝试所有与其长度相同的棍子
2、若正在替换一整根棍子中的第一根棍子,则返回失败(替换每个整根棍子中的第一根无法扭转失败局面)
3、保证安装上去的棍子顺序为从长到短,之后每次尝试新棍子,只会选择比最近安装上去的棍子更小的棍子
4、若正在替换一整根棍子中的最后一根棍子,则返回失败(替换每个整根棍子中的最后一根无法扭转失败局面)
(一)只采取了1、2剪枝方案的代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 1000
#define cls(array,num) memset(array,num,sizeof(array))
using namespace std;
int n,stick[MAXN],L;
bool bUsed[MAXN]; //标记木棒是否被用过
bool cmp(int a,int b)
{
    return a>b;
}
bool DFS(int R,int M) //还有R根木棒,剩余长度为M
{
    if(R==0&&M==0) return true; //任务完成
    if(M==0) M=L; //一根棍子拼完,开始拼新的一根
    for(int i=1;i<=n;i++)
    {
        if(!bUsed[i-1]&&stick[i]==stick[i-1]) continue; //剪枝1。之前一根木棒与这根木棒长度相同,但之前那根木棒装不上去,跳过
        if(bUsed[i]) continue;
        if(stick[i]<=M)
        {
            bUsed[i]=true;
            if(DFS(R-1,M-stick[i])) return true;
            else
            {
                bUsed[i]=false;
                if(M==L) return false; //剪枝2。在换第一根棍子,这是徒劳的,无论把第一根棍子换成其他任何棍子都将失败,返回false
            }
        }
    }
    return false;
}
int main()
{
    while(1)
    {
        cls(stick,0);
        int nTotalLen=0;
        cin>>n;
        if(!n) return 0;
        for(int i=1;i<=n;i++)
        {
            cin>>stick[i];
            nTotalLen+=stick[i];
        }
        sort(stick+1,stick+n+1,cmp);
        for(L=stick[n];L<=nTotalLen/2;L++) //L是每个拼好的棍子长度
        {
            cls(bUsed,0);
            if(nTotalLen%L) continue; //L不能整除总长度,显然不行,跳过
            if(DFS(n,L))
            {
                cout<<L<<endl;
                break;
            }
        }
        if(L>nTotalLen/2) cout<<nTotalLen<<endl; //如果之前所有长度都不可取,则说明处理后只能拼成一整根棍子
    }
    return 0;
}(二)采用了4种剪枝方案强剪枝的代码#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 1000
#define cls(array,num) memset(array,num,sizeof(array))
using namespace std;
int n,stick[MAXN],L;
bool bUsed[MAXN]; //标记木棒是否被用过
bool cmp(int a,int b)
{
    return a>b;
}
bool DFS(int R,int M) //还有R根木棒,剩余长度为M
{
    if(R==0&&M==0) return true; //任务完成
    if(M==0) M=L; //一根棍子拼完,开始拼新的一根
    for(int i=1;i<=n;i++)
    {
        if(!bUsed[i-1]&&stick[i]==stick[i-1]) continue; //剪枝1。之前一根木棒与这根木棒长度相同,但之前那根木棒装不上去,跳过
        if(bUsed[i]) continue;
        if(stick[i]<=M)
        {
            bUsed[i]=true;
            if(DFS(R-1,M-stick[i])) return true;
            else
            {
                bUsed[i]=false;
                if(M==L) return false; //剪枝2。在换第一根棍子,这是徒劳的,无论把第一根棍子换成其他任何棍子都将失败,返回false
            }
        }
    }
    return false;
}
int main()
{
    while(1)
    {
        cls(stick,0);
        int nTotalLen=0;
        cin>>n;
        if(!n) return 0;
        for(int i=1;i<=n;i++)
        {
            cin>>stick[i];
            nTotalLen+=stick[i];
        }
        sort(stick+1,stick+n+1,cmp);
        for(L=stick[n];L<=nTotalLen/2;L++) //L是每个拼好的棍子长度
        {
            cls(bUsed,0);
            if(nTotalLen%L) continue; //L不能整除总长度,显然不行,跳过
            if(DFS(n,L))
            {
                cout<<L<<endl;
                break;
            }
        }
        if(L>nTotalLen/2) cout<<nTotalLen<<endl; //如果之前所有长度都不可取,则说明处理后只能拼成一整根棍子
    }
    return 0;
}两种代码速度差异实在太大,令人惊讶![POJ 1011]Sticks(DFS剪枝),布布扣,bubuko.com
原文:http://blog.csdn.net/qpswwww/article/details/38732131