Poj1001小木棍

试题描述
乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,已知每段的长都不超过 50 。现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。
输入
第一行为一个单独的整数 N 表示砍过以后的小木棍的总数。其中N≤60。第二行为 N 个用空格隔开的正整数,表示 N 根小木棍的长度。
输出
输出仅一行,表示要求的原始木棍的最小可能长度。
输入示例
9
5 2 1 5 2 1 5 2 1
输出示例
6

很水的一道题,但是我一上来竟然以为是二分答案,但是并没有单调性

暴力枚举答案,然后用DFS判断是否可行,剪枝的话,只需要判断是否整出就可以了

下面给出代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
inline int min(int a,int b){return a<b?a:b;}
inline int max(int a,int b){return a>b?a:b;}
inline int rd(){
    int x=0,f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
inline void write(int x){
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
int n;
int a[10000];
int sum=0,maxn=0,minn=999999999;
void dfs(int res,int x,int target,int p){//res代表还需要几段,x代表当前段的长度,target是目标长度,p是当前段还需要多长 
    if(res==0){
        write(target);
        exit(0);
    }
    if(x==target){
        dfs(res-1,0,target,maxn);
        return ;
    }
    for(int i=p;i>=minn;i--){
        if(a[i]>0&&i+x<=target){
            a[i]--;
            dfs(res,x+i,target,i);
            a[i]++;
            if(x==0||x+i==target) break;
        }
    }
    return ;
}
int main(){
    n=rd();
    int i,j,k;
    int set=0;
    for(i=1;i<=n;i++){
        int x;
        x=rd();
        if(x<=50){
            set++;
            a[x]++;
            sum+=x;
            maxn=max(maxn,x);
            minn=min(minn,x);
        }
    }
    for(i=maxn;i<=sum/2;i++) if(sum%i==0) dfs(sum/i,0,i,maxn);//整个代码的关键,因为都是整数,所以无法整除的都不行 
    write(sum);
    return 0;
}
蒟蒻总是更懂你✿✿ヽ(°▽°)ノ✿
原文地址:https://www.cnblogs.com/WWHHTT/p/9816673.html