试题描述
|
乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,已知每段的长都不超过 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; }