搜索例题讲解--小木棍

题目

【 问题描述】
乔治有一些同样长的小木棍, 他把这些木棍随意砍成几段, 直到每段的长都
不超过 50。
现在, 他想把小木棍拼接成原来的样子, 但是却忘记了自己开始时有多少根
木棍和它们的长度。
给出每段小木棍的长度, 编程帮他找出原始木棍的最小可能长度。
【 输入】
输入文件共有二行。
第一行为一个单独的整数 N 表示砍过以后的小木棍的总数, 其中 N≤60, 第
二行为 N 个用空格隔开的正整数, 表示 N 根小木棍的长度。
【 输出】
输出文件仅一行, 表示要求的原始木棍的最小可能长度。
【 样例】
stick.in
9
5 2 1 5 2 1 5 2 1
stick.out
6

题解

#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
int cnt,n,a[61],sum,maxx;
int max(int x,int y){
    return x>y?x:y;
}// 判断大小 
void init(){
    int x;
    for(int i=1;i<=n;i++){
        scanf("%d",&x);
        if(x<=50){//当木棍长度大于50时,不能使用 
            a[++cnt]=x;
            sum+=x;//求和 
            maxx=max(x,maxx);//求最大的木棍长度 
        }
    }
}
int flag;
int b[61];
int t,m;
void search(int l,int s){//l是我枚举到了原始木棍根数的第l根
//s是我现在这一根枚举到的长度 
    if(flag)return;//不断弹出 
    if(l==t){//当完成时 
        flag=1;//标记 
        return;//弹出 
    }
    if(s==m){//当到达目标时 
        l++;//l累加 
        s=0;//重新计算s 
    }
    for(int i=1;i<=cnt;i++){//枚举每一个可能的木棍 
        if(a[i]+s>m || b[i])continue;//可行性 
        if(a[i-1]==a[i] && !b[i])continue;//可行性剪枝(参考解题报告第2条) 
        b[i]=1;//标记 
        search(l,s+a[i]);//接着搜 
        b[i]=0;//回溯 
        if(flag)return;//如果完成了,弹出 
        if(s==0)return;//当我有完成组,但是却没有全部完成时,也弹出
        //两者可以交换位置 
    }
}
int comp(const int &a,const int &b){
    return a>b;
}//快排从大到小 
int main(){
    freopen("stick.in","r",stdin);
    freopen("stick.out","w",stdout);//文件 
    int i,j,k; 
    scanf("%d",&n);
    init();
    std::sort(a+1,a+n+1,comp);//从大到小排序,方便匹配 
    for(i=maxx;i<=sum;i++){//从木棍最长的那一根到总和(剪枝) 
        if(sum%i==0){//如果可行 
            t=sum/i;//t是原始木棍有t根 
            m=i;//m是原始木棍每一根的长度 
            flag=0;//标记清零(可以不清) 
            search(0,0);//搜索 
            if(flag){//如果这一种原始木棍的解可行 
                printf("%d\n",i);//输出 
                return 0;//结束程序 
            }
        }
    }
    return 0;//可有可无 
}

下面是原创网址

http://blog.csdn.net/logo_FC/article/details/52741432

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值