小木棍[数据加强版]题解

小木棍 [数据加强版]

提高+/省选-

题目描述

乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过5050。

现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。

给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。

输入格式

共二行。

第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中N65

(管理员注:要把超过5050的长度自觉过滤掉,坑了很多人了!)

第二行为N个用空个隔开的正整数,表示N根小木棍的长度。

输出格式

一个数,表示要求的原始木棍的最小可能长度

输入输出样例

输入 #1
9
5 2 1 5 2 1 5 2 1
输出 #1
6

说明/提示

2017/08/05

数据时限修改:

-#17 #20 #22 #27 四组数据时限500ms500ms

-#21 #24 #28 #29 #30五组数据时限1000ms1000ms

其他时限改为300ms300ms(请放心食用)

暴搜肯定过不了,是要优化的

思路就是枚举小木棍的长度,从小到大枚举

为了方便,我们将没砍的叫长木棍,砍了的叫小木棍

  1. 以最长的小木棍的长度枚举,很容易理解吧,不可能砍了再变长
  2. 总长度必须是长木棍长度的倍数,这就不用解释了吧
  3. 一旦有一个分枝搜索失败,即有一根小木棍无论与其他的如何拼,也出现不了我们需要的长度,直接返回
  4. 相同的木棍不需要重复搜索,其中一个失败,其它肯定失败。
  5. 降序排序,sort一下
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int used[100],a[100],num,n,len,sum;
bool cmp(int x,int y)
{
    return x>y;
}
bool dfs(int stick,int cab,int last)
{
    if(stick>num) return true;                            //选够了num个了,并且所有小木棍都用完了,返回true, 
    if(cab==len)    return dfs(stick+1,0,1);    //拼成一个长木棍,再拼下一个长木棍 
    int ajh_ak_IOI=0;                                                                    
    for(int i=last;i<=n;i++)
    {
        if(!used[i]&&a[i]+cab<=len&&(ajh_ak_IOI!=a[i]))    //ajh_ak_IOI!=a[i],即剪枝4 
        {
            used[i]=1;
            if(dfs(stick,cab+a[i],i+1)) return true;            
            used[i]=0;
            ajh_ak_IOI=a[i];
            if(cab==0||cab+a[i]==len) return false ;//剪枝 3
        }
    }
    return false;
}
int main()
{
    while(cin>>n&&n)
    {
    int val=0;
    int Q,m=0;
    sum=0;
        for(int i=1;i<=n;i++)
        {
        scanf("%d",&Q);                                 
        if(Q<=50)                            //大于50的自动过滤掉,详见题目描述
        {
        a[++m]=Q;
        sum+=a[m];
        val=max(val,a[m]);
        }
        }
        n=m;
        sort(a+1,a+1+n,cmp);                //剪枝5 
        for(int i=val;i<=sum;i++)        //剪枝1 
        {
            if(sum%i!=0) continue;        //剪枝2 
            memset(used,0,sizeof(used));
            len=i;
            num=sum/i;
            if(dfs(1,0,1))
                break;            
        }
        cout<<len<<endl;
    }
}

 

调了3个小时代码不容易啊,支持一下再走吧

posted @ 2021-03-21 09:00  S_Curry  阅读(46)  评论(0编辑  收藏  举报