POJ1011 木棒

本文介绍了一种解决木棍还原问题的方法,即通过给定的一组被随机砍断后的木棍片段,寻找能够还原这些木棍到原始状态的最短长度。采用递归搜索算法并结合剪枝技巧,有效地减少了搜索空间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代码貌似不对,再放放… …

Time Limit: 1000MS Memory Limit: 10000K
Description

乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过50个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棍的长度都用大于零的整数表示。
Input

输入包含多组数据,每组数据包括两行。第一行是一个不超过64的整数,表示砍断之后共有多少节木棍。第二行是截断以后,所得到的各节木棍的长度。在最后一组数据之后,是一个零。
Output

为每组数据,分别输出原始木棒的可能最小长度,每组数据占一行。
Sample Input

9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0
Sample Output

6
5
Source

Central Europe 1995

解释:
看下面程序中的注释即可,
特别的,如果a[i]==rest,a[i]已经失败了,所以和它相同的rest长度肯定也会失败。
如果rest==len说明,说明在用a[i]之前没有用过任何木棍,那么以a[i]为第一根的情况失败了,那么这根木棍肯定拼不成目标长度,这个搜索也就没有意义了,直接跳出大循环。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int a[55];
bool vis[55];
int n; 
bool cmp(const int a,const int b)
{
    if(a>=b)
        return 1;
    else 
        return 0;
}
/*DFS:递归搜索,以剩下小棒数和拼接一根棒所需长度作为递归参数*/ 
bool dfs(int len,int num,int rest)//..,剩余的小棒数目 
{
    if(num==n && rest==0)/*当还需长度为0且未作接接的小棒个数为0时,说明拼接成功*/
    return len;
        return 1;
    if(rest==0)/*当完成拼接一个棒时,要重新进行下一根木棒拼接,给remains_len重新赋值*/
        rest=len;
    for(int i=0;i<n;i++)
    {
        if(vis[i]) /*已经作为成功拼接的小棒,不再作为拼接对象*/ 
            continue;
        if(rest>=a[i])
        {
            vis[i]=1;
            if(dfs(len,num-1,rest-a[i]))/*当接受这根小棒a[i],能完成所有任务,则返回成功拼接棒长*/ 
                return 1;
             vis[i]=0;
             if(a[i]==rest && len==rest)//这一步很重要,看上面的分析 
                break;
            while(a[i+1]==a[i])/*当a[i]不能完成任务,与它相同的小棒也不能完成任务(剪枝) */
                i++;
        }
    }
    return 0;
}
int main()
{
    while(scanf("%d",&n) && n)
    {
        int sum=0;
        int len;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            sum+=a[i];//a[1] a[2] a[3] a[4] 
        }
        sort(a,a+n,cmp);
        for(len=a[0];len<=sum;len++)/*每次尝试都要置所有小棒为可用*/
        {
            memset(vis,0,sizeof vis);
            if(sum%len==0)
            {
                if(dfs(len,n,0))//要拼成len的长度,用过的木棍数数量,剩余长度 
                {
                    cout<<len<<endl;
                    break;  
                }   
            }   
        }   
    }
    return 0;
}
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=70;
int n,a[N],cnt,maxn,goal;
bool cmp(int x,int y){return x>y;}
bool use[N];
inline void dfs(int ans,int num,int pre){//当前拼成的长度,目标大木棍的数目,当前搜索小木棍的位置 
    if(num==0){printf("%d\n",goal); exit(0);} 
    if(maxn-ans<a[cnt])return;    //"2"如果剩余长度小于最小长度return
    if(ans==goal)
    {
        dfs(0,num-1,1); //如果失败return
        return;
    }    
    for(register int i=pre;i<=cnt;i++)//"1"
        if(!use[i] && ans+a[i]<=goal){
            use[i]=1;
            dfs(ans+a[i],num,i+1);
            use[i]=0; 
            while(a[i]==a[i+1])i++;//"3"17,9,9,9,9,8,5,2……如果当前最长小棒为17,它与第一个9组合之后dfs发现不能拼成len
            if(ans+a[i]==goal || ans==0) return;   //"4"...8 7 5 3 3 2 2->15
        }//如果8+7成功,但后面的失败了,就不用再搜索8+5等等了。
        //反证法:因为如果8+后面的A成功了,且7+后面的B也成功了,那么8+7和A+B也都成功了,和结论相悖。 
        //a[i]为第一根的情况失败了,那么这根木棍肯定拼不成目标长度,
    return ; 
}
int main(){
    scanf("%d",&n);
    for(register int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        if(x<=50){a[++cnt]=x; maxn+=a[cnt];}
    }
    sort(a+1,a+cnt+1,cmp);   
    goal=a[1];
    while(goal<=maxn/2)//"0"  
    {
        if(maxn%goal==0) 
            dfs(0,maxn/goal,1);//当前拼成的长度,目标大木棍数目,上一个数的位置
        goal++;    
    }
    printf("%d\n",maxn);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值