深搜专题——木棒

这是我写过剪枝最多的题目
总计九个剪枝一个优化
最关键的是奇偶性剪枝,可行性剪枝,最优性剪枝

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
int A[70];
bool mark[70];
bool flag;
int n,s,ned;
void dfs(int x,int now,int sum,int jsum){
    //剪枝4:找到解后返回
    //剪枝5:若找到了ned-1根就直接返回
    //剪枝6:若相同,就跳过 
    //剪枝7:若该木棍长度加上原来长度大于期望长度,直接结束
    //剪枝8:类似于剪枝10
    //剪枝9:sum为0时该位是必取的
    //优化1:从取了的那一位向后循环 
    if(flag)return;//剪枝4 
    if(sum==ned-1){flag=1;return;}//剪枝5 
    if(x>s)return; 
    if((s&1)&&jsum<ned-sum-1)return;//剪枝8 
    FOR(i,now,n){ 
        if(mark[i])continue;
        if(x+A[i]>s)break;//剪枝7 
        mark[i]=1;
        if(x+A[i]==s)dfs(0,1,sum+1,jsum-(A[i]&1));
        else dfs(x+A[i],i+1,sum,jsum-(A[i]&1));
        mark[i]=0;
        if(!x)return;//剪枝9 
        while(A[i]==A[i+1])i++;//剪枝6 
    }
}
int main(){
    while(scanf("%d",&n)==1){
        if(n==0)break;
        int tta=0,jsum=0;
        FOR(i,1,n){
            scanf("%d",&A[i]);
            tta+=A[i];
            if(A[i]&1)jsum++;
        }
        sort(A+1,A+n+1);
        //剪枝1:不能整除
        //剪枝2:总条数小于期望条数
        //剪枝3:若枚举长度为奇数,而奇数个数小于需要个数 则不成立 
        DOR(i,tta,1){
            memset(mark,0,sizeof(mark));
            if(tta%i!=0)continue;//剪枝1 
            flag=0;
            s=tta/i,ned=i;
            if((s&1)&&(jsum<ned))continue;//剪枝3 
            if(i>n)continue;//剪枝2 
            dfs(0,1,0,jsum); 
            if(flag){
                printf("%d\n",s);
                break;
            }
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值