poj 1011 深搜

题意:长度相同的原始木棍被砍断,现在想将小木棍拼接成原始木棍,求原始木棍的最小可能长度。

分析:经典剪枝 

1.越长的木棍对后面木棍的约束力越大,因此要把小木棍排序,按木棍长度从大到小搜索,这样就能在尽可能靠近根的地方剪枝。

2.当前木棍能恰好填满一根原始木棍,但剩余的木棍无法组合出合法解,如果用更短的木棍组合来代替这根木棍,当前木棍不可能和剩下的其它木棍组合出合法解。

3.考虑每根原始木棍的第一根木棍,如果无法得出合法解,就不必考虑下一根木棍了,因为当前木棍一定是作为某根原始木棍的第一根木棍。

4.跳过重复长度的木棍。

5.最后一根木棍不必搜索,因为原始木棍长度是总木棍长度的约数。

 

 

int a[1000],b[1000];
int n;      //总数
int len;    //原始长度
int totallen;//总长度
int nowlen; //当前长度
int start;  //开始位置
int flag;   //标记

bool cmp(int a,int b){ return a>b; }

void DFS(){
    int i,tstart=start;
    for(i=tstart;i<n;i++) {
        if(flag) return;
        if(b[i]==0 && nowlen+a[i]<=len) {
            b[i]=1; nowlen+=a[i];
            if(nowlen==len) {
                nowlen=0;   totallen-=len;  start=1;
                if(totallen==len){flag=1;return;}
                DFS();
                nowlen=len; totallen+=len;  start=tstart;
            }
            else if(nowlen<len){start=i+1; DFS(); start=tstart;}
            b[i]=0; nowlen-=a[i];
            if(nowlen+a[i]==len||nowlen==0) break; 
            while(i<n-1&&a[i]==a[i+1]) i++;
        }
    }
}

int main() {
    while(cin>>n&&n!=0) {
        int i;
        totallen=nowlen=flag=0;
        for(i=0;i<n;i++) {
            cin>>a[i];
            totallen+=a[i];
            b[i]=0;
        }
        sort(a,a+n,cmp);
        int total=totallen;
        for(i=a[0];i<total;i++)
            if(total%i==0) {
                len=i;
                DFS();
                if(flag) {
                    cout<<i<<endl;
                    break;
                }
            }
        if(i==total) cout<<total<<endl;
    }
    return 0;
}

 

posted @ 2013-06-20 19:41  心向往之  阅读(199)  评论(0编辑  收藏  举报