深搜剪枝——小木棍

题目描述:

乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50 。现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。

输入格式
第一行为一个单独的整数 N表示砍过以后的小木棍的总数。 第二行为 N个用空格隔开的正整数,表示 N 根小木棍的长度。

输出格式
输出仅一行,表示要求的原始木棍的最小可能长度。

样例
样例输入
9
5 2 1 5 2 1 5 2 1

样例输出
6

数据范围与提示
1<=N<=60

题意:同样长的几根木棍分成几段小木棍,求原始木棍的长度

思路:这几根木棍同样长,那么分成的小木棍长度的总和能被木棍长度整除,并且木棍的长度大于等于最大小木棍的长度,小于等于木棍总长度,所以在这之间从小到大寻找木棍长度len,然后与总长度相除,寻找到一共需要m根木棍,然后通过深搜判断小木棍能否满足组成m根长度为len的木棍,如果能组成,即为最小木棍长度。

#include <bits/stdc++.h>
using namespace std;
const int M = 1e5 + 10;
///a[]存储小木棍长度,len木棍长度,maxx总长度
///book[]标记,n小木棍数量,m需要多少根木棍
int a[M], len, maxx, book[M], n, m;
///布尔标记
bool flag;
///数组从大到小排序
bool cmp(int x, int y)
{
    return x > y;
}
void dfs(int k, int use, int l)
/*
k表示第几根木棍
use表示使用的小木棍,然后从下一个小木棍开始找
l表示木棍长度减去使用的小木棍长度后的长度
*/
{
    int i, j;
    ///木棍长度为0表示找完一根木棍
    ///开始找下一根木棍
    if (l == 0)
    {
        ///当找完这根木棍后木棍数等于所需木棍数时返回
        if (k == m)
        {
            flag = true;
            return;
        }
        ///从大到小遍历小木棍的长度,寻找到未标记的小木棍
        for (i = 1; i <= n; i++)
        {
            if (book[i] == 0)
                break;
        }
        ///使用未标记的长度最大的小木棍开始拼接下一个木棍
        book[i] = 1;
        ///这里开始拼接第k+1个的木棍,长度从len开始减
        dfs(k + 1, i, len - a[i]);
        book[i] = 0;///回溯
    }
    ///从使用过的小木棍的下一个小木棍开始找
    for (i = use + 1; i <= n; i++)
    {
        ///保证小木棍未使用过并且不能大于当前木棍所需长度
        if (book[i] == 0 && a[i] <= l)
        {
            book[i] = 1;
            dfs(k, i, l - a[i]);
            book[i] = 0;    ///回溯
            ///当len满足条件被标记时,直接返回
            if (flag == true)
                return;
            ///将重复的小木棍删去,剪枝
            while (a[i] == a[i + 1])
                i++;
        }
    }
}
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        int i, j, k, s = 0;
        memset(book, 0, sizeof(book));
        maxx = 0;

        for (i = 1; i <= n; i++)
        {
            cin >> a[i];
            maxx += a[i];
        }

        sort(a + 1, a + 1 + n, cmp);
        ///木棍的长度len大于等于最长的小木棍小于等于总长度
        for (len = a[1]; len <= maxx; len++)///遍历
        {
            ///木棍是相等的,所以木棍的长度能整除木棍总长度
            if (maxx % len != 0)
                continue;

            flag = false;
            ///找到后看需要几根木棍
            m = maxx / len;
            ///深搜看小木棍是否能够组成m根长度为len的木棍
            ///从第一个开始,标记第一个小木棍
            book[1] = 1;
            dfs(1, 1, len - a[1]);
            ///因为木棍长度是从小到大遍历的,所以找到的满足条件的第一个木棍长度即为最小长度
            if (flag == true)
            {
                cout << len << endl;
                break;
            }
        }
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值