poj1011 dfs 剪枝

这道题与poj2362类似,对剪枝的要求更多了。题目大意为原本有许多等长的棍子,被切碎了,现在要求出原来棍子最小的可能长度。

依旧是将棍子按照从大到小排序,减少递归次数。

因为所有棍子都要用到,所以原来棍子长度一定>=最长的一根棍子。求出棍子总长度sum,然后从最长的一根棍子长度开始,向上枚举,当sum/%i==0 时 ,说明原来棍子有可能是这么长,再进行DFS 从而判断。

以下为代码:

<pre name="code" class="cpp">#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

int a[80],b[80],n,flag;
bool cmp(int x,int y)
{
    return x>y;
}

void dfs(int len,int i,int step,int num,int k) //len为当前长度,i为目标长度,step当前边数,num目标边数,k记录下一根棍子搜索位置
{
    if(step==num){ //递归边界
        flag=1;
        return ;
    }
    int ret=-1;
    for(int j=k;j<n;j++){
        if(flag)return ;
        if(b[j] || a[j]==ret) continue; //剪枝:ret记录上一根不合要求的棍子

        b[j]=1; //标记
        if(len+a[j]<i)  dfs(len+a[j],i,step,num,j),ret=a[j];
        if(len+a[j]==i) dfs(0,i,step+1,num,0),ret=a[j];
        b[j]=0; //还原

        if(len==0) return ; //重要剪枝:若凑大棍子的第一根小棍子不合要求,则不要继续往后搜索,直接返回
    }
}
int main()
{
  //  freopen("in.txt","r",stdin);
    while(1){
        scanf("%d",&n);
        if(!n) break;
        memset(a,0,sizeof(a));

        int sum=0;
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
            sum+=a[i];
        }
        int num;
        sort(a,a+n,cmp);
        for(int i=a[0];i<=sum;i++){ //寻找最小的可能的原长
            if(sum%i==0){
                flag=0;
                num=sum/i;
                memset(b,0,sizeof(b));
                dfs(0,i,0,num,0);
                if(flag)break;
            }
        }
        printf("%d\n",sum/num);
    }
    return 0;
}




                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值