小木棍c++

题目描述

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

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

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

输入格式

第一行是一个整数 �n,表示小木棍的个数。
第二行有 �n 个整数,表示各个木棍的长度 ��ai​。

输出格式

输出一行一个整数表示答案。

输入输出样例

输入 #1复制

9
5 2 1 5 2 1 5 2 1

输出 #1复制

6

说明/提示

对于全部测试点,1≤�≤651≤n≤65,1≤��≤501≤ai​≤50。

暴搜的思路并不难想到,主要难点是各种优化、各种剪枝:

  1. 预先处理出所有木棍的总长度,且保证枚举答案的值能被总长度整除。

  2. 每根木棍的长度可用桶来存储,并且预先处理出最长的和最短的木棍的长度,搜索时从最大长度到最小长度递减枚举。

  3. 若拼接当前木棍时已用了一根长为X的木棍,则dfs时从长度X开始搜索。

  4. 若某组拼接不成立,且此时 已拼接的长度为0 或 当前已拼接的长度与刚才枚举的长度之和为最终枚举的答案 时,则可直接跳出循环,因为此时继续枚举其它更小的值时,显然可能情况更少,且同样凑不完。

  5. 注意常数不要太大。

附上代码:

#include<cstdio>
#include<cstdlib>
const int N = 70 ;
int n , cnt , tot , maxn , minn , tm[ N ] /* 2 */ ; 
void dfs( int res , int sum , int target , int p ) {
    if( res == 0 ) {
        printf("%d", target  );
        exit( 0 );
    }
    if( sum == target ) {
        dfs( res - 1 , 0 , target , maxn );
        return;
    }
    for( int i = p ; i >= minn ; i -- ) { // 2  3 
        if( tm[ i ] && i + sum <= target ) {
            tm[ i ] -- ;
            dfs( res , sum + i , target , i );
            tm[ i ] ++ ;
            if ( sum == 0 || sum + i == target )  //4
                break;
        }
    }
    return;
}
int main() {
    scanf("%d" , &n ) ;
    minn = N ;
    int temp;
    while( n -- ) {
        scanf("%d" , &temp );
        if( temp <= 50 ) {
            cnt ++;
            tm[ temp ] ++;
            tot += temp;
            maxn = maxn > temp ? maxn : temp ;   //1
            minn = minn < temp ? minn : temp ;
        }
    }
    temp = tot >> 1;
    for( int i = maxn ; i <= temp ; i ++ ) {
        if( tot % i == 0 ) {
            dfs( tot / i , 0 , i , maxn );
        }
    }
    printf("%d" , tot );
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值