洛谷P1120 小木棍(sticks数据加强版)

时间:2024-04-30 14:57:31

题目描述

乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50。

现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。

给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。

输入输出格式

输入格式:

输入文件共有二行。

第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中N≤65

(管理员注:要把超过50的长度自觉过滤掉,坑了很多人了!)

第二行为N个用空个隔开的正整数,表示N根小木棍的长度。

输出格式:

输出文件仅一行,表示要求的原始木棍的最小可能长度

输入输出样例

输入样例#1:
9
5 2 1 5 2 1 5 2 1
输出样例#1:
6

把普通版的代码改了读入直接交上去,1700+ms爬过去了……
 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int st[],num;//个数
bool vis[];
int n,sum;
int len;
int cmp(const int a,const int b){return a>b;}
bool dfs(int s,int now,int p){
//目前在组装第s根棍子,这根棍子已经组装了now长度,从所有短木棍中的第p+1个开始枚举
bool flag=false;
if(now==)flag=;
if(s==num)return true;//拼够数量了
for(int i=p+;i<=n;i++){
if(vis[i])continue;
if(now+st[i]==len){
vis[i]=;
if(dfs(s+,,))return true;//开始拼下一根
vis[i]=;//先还原
return false;//再返回
}
else if(now+st[i]<len){
vis[i]=;
if(dfs(s,now+st[i],i))return true;//尝试继续拼这一根
vis[i]=;
if(flag)return false;
//开始拼一根木棍时,如果用剩下最长的木棍开始搜不能成功,用比它更短的搜也没有意义,所以跳出
while(st[i]==st[i+])i++;//不再尝试相同长度的
}
}
return false;
}
int main(){
scanf("%d",&n);
sum=;
int i,j;
int tmp=n;
int tmps;
int cct=;
while(tmp--){
scanf("%d",&tmps);
if(tmps>)continue;
cct++;
st[cct]=tmps;
sum+=tmps;
}
n=cct;
/*
for(i=1;i<=n;i++){
scanf("%d",&st[i]); sum+=st[i];
}*/
sort(st+,st+n+,cmp);//从大到小排序,开始枚举
for(i=st[];i<=sum;i++){//枚举长度
if(sum%i!=)continue;//只有能整除,才尝试按这个长度拼
num=sum/i;//预计拼的个数
len=i;
memset(vis,,sizeof vis);
if(dfs(,,)){
printf("%d\n",i);//成功就输出
break;
}
}
return ;
}