资源限制
时间限制:1.0s 内存限制:999.4MB
Sticks
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 113547 Accepted: 26078
问题描述
George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero.
输入格式
The input contains blocks of 2 lines. The first line contains the number of sticks parts after cutting, there are at most 64 sticks. The second line contains the lengths of those parts separated by the space. The last line of the file contains zero.
输出格式
The output should contains the smallest possible length of original sticks, one per line.
样例输入
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0
样例输出
5
6
题目大意:
乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过50个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棍的长度都用大于零的整数表示。
1)不要在同一个位置多次尝试相同长度的木棒(在某一次拼接时选择长度为s的木棒导致拼接失败,则在同一位置尝试下一根木棒时,要跳过所有长度为s的木棒)
2)如果由于以后的拼接失败,需要重新调整第i根棍子的拼法,则不会考虑替换第i根棍子中的第一根木棒。
3)不要希望通过仅仅替换已经拼好的棍子的最后一根木棒就能改变失败的局面。
4)拼每一根棍子的时候,应确保已经拼好的部分,长度是从长到短排列的(因为我们应该先拼长的,长的可能性小)
排除方法:每次找一根木棒的时候,只要这不是一根棍子的第一条木棒,那么不应该从下标为0的木棒开始找,而应该从刚刚接上去的那条木棒的下一条开始找(当然,我们要先对木棒进行从大到小的排序)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int a[105],n,cnt,num,vis[105]; //a数组用来记录数据,n是数据个数,vis是选中标记数组
int cmp(int a,int b) //排序函数
{
return a > b;
}
bool dfs(int sticks,int now,int last)
{
//sticks:表示当前处理第几根新棒子了。
//cab:表示当前这个棒子已经拼接到多长了。
//last:表示用到了第几根砍断的棒子了
if(sticks >= cnt + 1)return true; //当处理过的棒子多余实际个数时,返回true
if(now == num)return dfs(sticks + 1,0,1); //当现在处理的这根棒子已经达到实际长度时,now归零,sticks+1
int fail = 0;// 记录连接失败的棒子的长度,防止后面相同尺寸的棒子在进行连接
for(int i = last;i <= n;i++) //从last开始枚举
{
if(vis[i] || a[i] == fail || now + a[i] > num)continue; //vis数组和合理性判断,访问过或者和前面失败的尺寸一样或者加上这条棒子就超过尺寸了,就跳出循环
vis[i] = 1; //将这条棒子设为已经访问
if(dfs(sticks,now + a[i],i + 1))return true; //将now加上本条棒子的尺寸
vis[i] = 0; //回溯
fail = a[i]; //将fail值记为ai
if(now == 0 || now + a[i] == num)return false; //出现这样的情况意味着只能这样选,还是选不了就意味着这种状态不合法。
}
return false;
}
int main()
{
while(~scanf("%d",&n) && n) //多组输入,遇零停止
{
int mx = 0,sum = 0; //记录总和和最大值,答案一定在这个区间中
for(int i = 1;i <= n;i++) //输入数据寻找最大直
{
scanf("%d",&a[i]);
mx = max(a[i],mx);
sum += a[i];
}
sort(a + 1,a + 1 + n,cmp); //大到小排序
for(int i = mx;i <= sum;i++) //遍历目标答案
{
if(sum % i)continue; //如果枚举出来的答案不能被段数整除,则跳过
cnt = sum / i;num = i; //因为刚开始时每段的木棒都是一样长的,所以可以计算出原始的长度和根数,其中cnt是根数
memset(vis,0,sizeof(vis)); //初始化标记数组
if(dfs(1,0,1)) //开始深搜
{
printf("%d\n",i); //如果有满足条件的输出
break;
}
}
}
return 0;
}