北大oj1011——Sticks

Sticks

Time Limit: 1000MS Memory Limit: 10000K

Description

George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero.

Input

The input contains blocks of 2 lines. The first line contains the number of sticks parts after cutting, there are at most 64 sticks. The second line contains the lengths of those parts separated by the space. The last line of the file contains zero.

Output

The output should contains the smallest possible length of original sticks, one per line.

Sample Input

9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0

Sample Output

6
5

解决了好久,差点心态崩了。
深度优先搜索。
剪枝方法:
1.由大到小进行搜索,因为大数更容易满足要求填满一根棍子,下一次搜索总数就减少了,而且大数更容易发现当前能不能行。
2.去重搜索,如果用了一根棍子发现找不到满足要求的其他棍子,那么同样长度的棍子都是不满足条件的。
3.以当前剩余长度的棍子为起始搜索,避免了中间不必要的环节。
4.减半搜索,满足条件的棍子只能是总值能整除的数,所以当搜索到总值减半的值还搜不到答案时,那么答案就是总值。

让我非常疑惑的是,我的深搜方法不知道是有什么问题,搜遍了网上提供的各项测试数据都能正常通过,但就是通不过poj,头疼,所以借鉴了一下大牛们的写法。调用函数时把要搜几根棍子传进去,一直到棍子都满足条件了再跳出函数,并且把列表回溯。

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

bool isSuccess;
int a[71];
int gunZiLen;

void getContantGun(int lastN, int index, int useNum) {
    a[index]--;

    if (useNum == 0) {
        isSuccess = true;
    }
    if (!isSuccess) {
        lastN -= index;
        if (lastN > 0) {
            for (int i = min(lastN, index); i > 0; i--) {
                if (a[i] > 0) {
                    getContantGun(lastN, i, useNum);
                }
            }
        }
        else if (lastN == 0) {
            int maxNum = 50;
            while (a[maxNum] == 0) {
                maxNum--;
            }
            getContantGun(gunZiLen, maxNum, useNum - 1);
        }
    }
    a[index]++;
}

int main1011()
{
    int n;
    while (cin >> n) {
        if (n == 0) {
            break;
        }
        int cnt = 0;
        int maxNum = 0;
        memset(a, 0, sizeof(a));
        for (int j = 0; j < n; j++) {
            int x;
            cin >> x;
            cnt += x;
            a[x] ++;
            maxNum = max(maxNum, x);
        }

        isSuccess = false;
        for (int i = maxNum; i <= cnt / 2 + 1; i++) {
            if (cnt % i == 0) {
                gunZiLen = i;
                int useCnt = cnt / gunZiLen;
                getContantGun(gunZiLen, maxNum, useCnt);
                if (isSuccess) {
                    cout << gunZiLen << endl;
                    break;
                }
            }
        }
        if (!isSuccess) {
            cout << cnt << endl;
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

椰子糖莫莫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值