小木棍
题目描述
乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过 50 50 50。
现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。
给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。
输入格式
第一行是一个整数
n
n
n,表示小木棍的个数。
第二行有
n
n
n 个整数,表示各个木棍的长度
a
i
a_i
ai。
输出格式
输出一行一个整数表示答案。
样例 #1
样例输入 #1
9
5 2 1 5 2 1 5 2 1
样例输出 #1
6
提示
对于全部测试点, 1 ≤ n ≤ 65 1 \leq n \leq 65 1≤n≤65, 1 ≤ a i ≤ 50 1 \leq a_i \leq 50 1≤ai≤50。
代码
#include<bits/stdc++.h>
using namespace std;
int n,cnt=1,a[100],sum,len,m,ne[100];
bool used[50],ok=0;
struct cmp{
bool operator ()(const int &a,const int &b){
return a>b;
}
};
void dfs(int k,int last,int rest){
int i;
if (rest==0){
if (k==m){ok=1;return;}
for (i=1;i<=cnt;i++)
if (used[i]==0) break;
used[i]=1;
dfs(k+1,i,len-a[i]);
used[i]=0;
if(ok) return;
}
for (i=last+1;i<=cnt;i++){
if (a[i]<=rest and !used[i]) break;
}
for(;i<=cnt;i++){
if (used[i]) continue;
used[i]=1;
dfs(k,i,rest-a[i]);
used[i]=0;
if (ok) return;
if (rest==a[i]) return;
i=ne[i];
}
}
int main(){
cin>>n;
for (int i=1;i<=n;i++){
cin>>a[cnt];
if (a[cnt]<=50){
sum+=a[cnt];
cnt++;
}
}
cnt--;
sort(a+1,a+1+cnt,cmp());
ne[cnt]=cnt;
for (int i=cnt-1;i>0;i--){
if (a[i]==a[ne[i+1]]) ne[i]=ne[i+1];
else ne[i]=i;
}
for (len=a[1];len<=sum/2;len++){
if (sum%len!=0) continue;
m=sum/len;
ok=0;
used[1]=1;
dfs(1,1,len-a[1]);
used[1]=0;
if (ok) {cout<<len;return 0;}
}
cout<<sum;
return 0;
}
分析
struct cmp{
bool operator ()(const int &a,const int &b){
return a>b;
}
};
sort(a+1,a+1+cnt,cmp());
利用functor提高sort程序效率,比起函数更快
2.
ne[cnt]=cnt;
for (int i=cnt-1;i>0;i--){
if (a[i]==a[ne[i+1]]) ne[i]=ne[i+1];
else ne[i]=i;
}
排除等效冗余,用ne[i]表示排序后对于a[i]的最后一个数的下标
3.sum/2
,选一半即可,若无解,则输出sum
4.输入时要判断是否不大于50,舍弃部分数据
5.if (sum%len!=0) continue;
排除不可能的len
6.
if (ok) return;
立即回溯,不在搜索
7.if (rest==a[i]) return;
在dfs(k,i,rest-a[i]);
之后,rest==0一定成立,不再搜索