POJ-1011 sticks

【本以为是个青铜,其实是个王者系列】

一开始只是简单的深搜,结果显然TLE

本题数据卡得非常紧。4种主要剪枝缺一不可。

此处粘上某博客解释,感觉很清晰。

-------------分割线-----------------

思路启发:

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

    如果当前木棍能恰好填满一根原始木棍,但因剩余的木棍无法组合出合法解而返回,那么让我们考虑接下来的两种策略,一是用更长的木棍来代替当前木棍,显然这样总长度会超过原始木棍的长度,违法。二是用更短的木棍组合来代替这根木棍,他们的总长恰好是当前木棍的长度,但是由于这些替代木棍在后面的搜索中无法得到合法解,当前木棍也不可能替代这些木棍组合出合法解。因为当前木棍的做的事这些替代木棍也能做到。所以,当出现加上某根木棍恰好能填满一根原始木棍,但由在后面的搜索中失败了,就不必考虑其他木棍了,直接退出当前的枚举。(剪枝二)

    显然最后一根木棍是不必搜索的,因为原始木棍长度是总木棍长度的约数。(算不上剪枝)

    考虑每根原始木棍的第一根木棍,如果当前枚举的木棍长度无法得出合法解,就不必考虑下一根木棍了,当前木棍一定是作为某根原始木棍的第一根木棍的,现在不行,以后也不可能得出合法解。也就是说每根原始木棍的第一根小木棍一定要成功,否则就返回。(剪枝四)

    剩下一个通用的剪枝就是跳过重复长度的木棍,当前木棍跟它后面木棍的无法得出合法解,后面跟它一样长度的木棍也不可能得到合法解,因为后面相同长度木棍能做到的,前面这根木棍也能做到。(剪枝五)

AC代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
//tle了两次。两处modify剪枝 解决 。剪枝的魔力 ,缺一不可。 
//这里放几个版本的解释: 
/*:版本1: 
  当出现加上某根木棍恰好能填满一根原始木棍,但由在后面的
    搜索中失败了,就不必考虑其他木棍了,直接退出当前的枚举。
:考虑每根原始木棍的第一根木棍,如果当前枚举的木棍长度无
    法得出合法解,就不必考虑下一根木棍了,当前木棍一定是作
    为某根原始木棍的第一根木棍的,现在不行,以后也不可能得
    出合法解。也就是说每根原始木棍的第一根小木棍一定要成
    功,否则就返回。
:剩下一个通用的剪枝就是跳过重复长度的木棍,当前木棍跟
    它后面木棍的无法得出合法解,后面跟它一样长度的木棍也
     不可能得到合法解,因为后面相同长度木棍能做到的,前面这
     根木棍也能做到。
 */
 /*版本2: 
 。若当前木棒不可用,那么与这根小木棒长度相同的木棒也将不可用,
 直接跳过(剪枝),而且若这个小木棒的长度刚好是reamins_len的长度,
 那么更能说明后面的不能匹配了,
 因为如此合适的小棒被接收都不能导至试探成功,后面的小棒更不可能,
 直接返回0(试探失败 )(剪枝)。
 还有就是如果len=remains_len(说明这是新一根原棒,还没有进行匹配),
 而在预先判断匹配与否时已经判断不能匹配,这样都不能匹配,
 那么说明以后都不能匹配了(这就是深搜的效果了)。返回0(试探失败)(剪枝)。 
 */ 
 //https://blog.csdn.net/u011721440/article/details/19631927;目前看到的最好版本
 /*
 
 */ 
using namespace std;
int a[100];
int sum;
int n;
int aim;
int used[100];
int cmp(const int a,const int b){
    return a>b;
}
int dfs(int num,int len,int pos){
    bool sign=(len==0?true:false);//modify2
    if(num==sum){
        return 1;
    }
    int i;
    for(i=pos;i<n;i++){
        if(used[i]==0&&len+a[i]==aim){
            used[i]=1;
            if(dfs(num+1,0,0)==1)return 1;
            used[i]=0;
            return false; //modify1
            //while(a[i]==a[i+1])i++;
        }
        else if(used[i]==0&&len+a[i]<aim){
            used[i]=1;
            if(dfs(num,len+a[i],i+1)==1)return 1;
            used[i]=0;
            if(sign) return false;//modify2
            while(a[i]==a[i+1])i++;
        }
        if(used[i]==0)while(a[i]==a[i+1])i++;
    }
    return 0;
}

int main(void){
    while(scanf("%d",&n)==1&&n!=0){
    
        int total=0;
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
            total+=a[i];
        }
        sort(a,a+n,cmp);
        for(int i=a[0];i<=total;i++){
            if(total%i==0){
                sum=total/i;
                aim=i;
                memset(used,0,sizeof(used));
                if(dfs(0,0,0)==1){
                    printf("%d\n",i);
                    break;
                } 
            }
        }
    }
    return 0;
}

 

posted @ 2018-04-25 23:44  KYSpring  阅读(111)  评论(0编辑  收藏  举报