D - 小木棒

D - 小木棒

Time Limit: 1000/1000MS (C++/Others) Memory Limit: 65536/65536KB (C++/Others)

Problem Description

George有一些长度相等的木棒,他随意的将这些木棒切成长度最多是50的小木棒。麻烦来了,他现在想将这些杂乱的小木棒恢复到原来的木棒,但是他忘记了原来到木棒的数量和长度。请你帮助他设计一个程序计算出原来木棒可能的最小长度,所有小木棒的长度均表示为大于0的整数。

Input

每组输入数据包括两行。第一行是George切后小木棒的个数,最多有64根小木棒;第二行是这些小木棒的长度,这些长度表示为空格分开的整数。输入样例以整数0表示结束。

Output

输出一行,即为原始木棒可能的最小长度。

Sample Input

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

Sample Output

6
5




#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

int a[105], n, now;
bool vis[105];

bool dfs(int len, int cnt, int p){ //当前需要的木棍长度,当前已拼接的木棍个数,当前拼接的下标

    if(cnt == n) return true;      //已经拼成了n个木棍,可行
    if(len == 0) {                 //当前需要的木棍长度为0
        len = now;                 //把len置为当前检测长度 now
        p = n;                     //把搜索下标置为最大
    }

    int lst = 0;
    for(int i=p-1; i>=0; i--){     //剪枝:再同一根木棍的拼凑中,不用反复搜索较大木棍,[0, p]
        if(!vis[i] && a[i] <= len && a[i] != lst){ //剪枝:如果和上一个不可行长度相等,则跳过
            vis[i] = true;         // 取当前木棍 再搜索
            if(dfs(len - a[i], cnt + 1, i)) // 可行 return true
                return true;
            vis[i] = false;       // 不可行,则需要回退状态,不选当前木棍
            lst = a[i];           // 记录上一个不可行的木棍,和这个相等的都不用判
            if(len == now) return false; // 剪枝: 如果有任何一个不能构成len长度,则return false
        }
    }
    return false;
}

int main(){
    int maxx, sum, ans; // 分别记录最长的木棍,总长度,答案
    while(~scanf("%d", &n) && n){
        sum = 0;
        for(int i=0; i<n; i++) {
            scanf("%d", &a[i]);
            sum += a[i];
        }
        sort(a, a+n);  //sort 默认升序排序
        maxx = a[n-1]; //取最大的元素
        ans = sum;     //ans初始化为sum,如果[maxx, sum/2]范围内都找不到解,一定是全部合成一根

        for(int i=maxx; i<=sum/2; i++){ //剪枝:如果[maxx, sum/2]范围内都找不到解,答案是sum
            if(sum%i == 0) {   //剪枝:当i是sum的因子,才有可能是原木棍长度
                memset(vis, 0, sizeof vis); //每次搜索前,把所有木棍置为未选择状态
                now = i;                    //当前搜索的目标长度是i

                if(dfs(i, 0, n)) {
                    ans = i;                //剪枝:找到的第一组可行解直接跳出
                    break;
                }
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

 

posted @ 2018-12-26 18:06  山川湖海*  阅读(319)  评论(0编辑  收藏  举报