poj1011

这道题提交20多次才通过。主要原因是没有每次将flag标志重置为false。
思想:木棒长度肯定介于最大的木棒长度和木棒总长度之间,且是木棒总长度的约数(因素)。
第一步:对输入的从大到小排序,同时求出木棒总长度。
第二走:从最长木棒到木棒总长度之间一次循环,显然数组的一个根就是最长木棒。
第三步:深度搜索。记录当前拼凑木棒的长度,当前数组访问下表,当前深搜深度。
(1)如果当前拼凑木棒长度为0,那么取出没有访问过的最长木棒,继续深搜。
(2)如果当前拼凑木棒长度==需要拼凑出来的木棒长度,本次拼凑完成。如果深度为总木棒数,表示深搜完成,退出。
否则,继续深搜。
(3)如果当前拼凑木棒长度小于等于需要拼凑出来的木棒长度,则开始查找,查找未访问的,且待用长度与目前拼凑木棒长度小于等于拼凑出来的木棒长度。
  需要剪枝,如果上一个拼凑不成功,且这一个和上一个长度一致,则这一个也和上次一样不会成功。
  否则,继续深搜。
  拼凑不成功,必须回溯,即将未拼凑成功的重置未访问标志。
深搜完成,可以提前退出。找到木棒长度,立即终止循环。
肯定会有答案出现,所有搜索不成功时,木棒总长度即为答案。


#include<iostream>
#include<algorithm>

#define SIZE 65


using namespace std;



int n;//木棒数目 
int a[SIZE];//木棒长度数组   
int visit[SIZE];//访问标志数组 
int len;//当前测试的长度 
int flag = 0;//完成标志 

int compare(int a, int b){  
      if( a>b)
        return 1;
      return 0;
} 

//dep表示已经使用过的小棒数目,curlen表示当前需要拼凑的小棒长度,pos表示当前数组下标 
void dfs(int dep,int curlen,int pos ){
  //  cout<<dep<<" "<<curlen<<" "<<pos<<endl;
    if(flag )
      return ;
    if(curlen == 0){
        int k= 0;
        while(visit[k])
          k++;
        visit[k] = 1;
        dfs(dep + 1, a[k], k + 1); 
        //visit[k] = 0; //如果没有成功,需要回溯 
        return ; //如果未成功,直接退出 
    }
       
    if(curlen == len){//拼凑完成
      if(dep == n) flag = 1;
      else dfs(dep, 0, 0);  
      return ;    // 如果未成功,直接退出 
    }     
    
     for(int i = pos; i < n; i ++)//当前curlen未拼凑满时 
        if(!visit[i] && curlen + a[i] <= len)//可能拼凑成功 
           {
            if(!visit[i-1] && a[i] == a[i-1])//上一个未被访问,上一个和这一个数值一样,则这一个也不会被访问 
                continue; 
            visit[i] = 1;//否则,可以拼凑 
            dfs(dep + 1, curlen + a[i], i + 1);
            visit[i] = 0;//如果未成功,则回溯 
        } 
}     

int main(void){
    
    while(cin>>n && n>0){
        int sum = 0;//记录木棒总长度 
          //接收输入 
        flag = 0;
        for(int i=0;i<n;i++){
            cin>>a[i];
            sum += a[i]; 
        }  
        sort(a,a+n,compare);
        for(len=a[0];len<sum;len++){
             if(sum % len == 0){ 
                memset(visit,0,sizeof(visit));//清空访问数组 
                dfs(0, 0, 0);
                if(flag) break;
            } 
        } 
        cout<<len<<endl;     
    }    
    //system("pause");
    return 0;
}       
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值