poj 1011-小白算法练习 Sticks 从最简单的做起 dfs+剪枝

来源:互联网 发布:python notebook 使用 编辑:程序博客网 时间:2024/06/06 00:28
Sticks
Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 145712 Accepted: 34485

Description

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.

Input

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.

Output

The output should contains the smallest possible length of original sticks, one per line.

Sample Input

95 2 1 5 2 1 5 2 141 2 3 40
再测这组数据看看
9
15 11 8 8 8 4 3 2 1 结果:20

Sample Output

65

翻译:这也是学英语的一部分

乔治拿了等长度的木条,直至把这些木条分成不超过50的部分,现在他想还原这些木条,但他忘记了原来是那个和原来多长,请帮他找到木条可能的最小值


输入:包括两行,第一行:分成多少条小木条(最多64条)

     第二行:每条木条的长度

输出:一行,最小的可能的原木条长度

最初思路:

我们可以知道所有的原木条长度是一样的,而且>=5.我们知道分成小木条之后,这些小木条之和肯定是原木条长度的倍数,长度不会多出来。以

95 2 1 5 2 1 5 2 1
为例。sum=24  那么 只要24/X是整数且X越小越好 且X>=小木条最大的数,求出X就好了。

然而只要考虑这些就够了吗,结果是否定的。我一开始认为只要求满足的最小约数就好了,但是想一下,你算出来的最小约数真的能被这些小木条凑起来吗,万一你的约数是7,但你的小木条都凑不出7,那不就开玩笑了吗。所以怎么办?但是我们可以知道原木条的长度肯定是>=小木条最大值 && 原木条的长度是sum的约数

解决问题:

那我们肯定是要找匹配这些约数,看哪个最小的约数可以满足让这些小木条正好可以凑起来。我们肯定是要一个一个的找喽---索搜

我们最好从大到小的找(所以我们从大到小排序),这样可以减少运行量,那我们怎么样才算找到呢?我们先拿出第一个数,发现还差一点点,找第二个数,直至找到相等,如果没有相等,则这个约数不是要找的数。如果这k个数加起来是这个数,我们还要往下看,剩下的数还有没有加到这个约数。直至结束。那么结束条件是什么呢?我们每加上一个数,那么就设这个数列的长度+1,如果这个数列长度==原数列,那么我们说,确实是这个数。

代码:

#include<iostream>#include<algorithm>#include<cstring>using namespace std;int vis[65];int t[65]; bool flag;bool cmp(int a,int b){return a>b;}//cur_len为当前的长度(如果有一组数==len[约数]会置0)//strlen为数列的长度//maxlen是小木条的数量(最后是数列长度==小木条数量-->成功)//len是约数 void dfs(int cur_len,int strlen,int index,int len,int maxlen){  if(flag) return;if(cur_len==len){if(strlen==maxlen){flag=true;}else{dfs(0,strlen,0,len,maxlen);}return;}if(cur_len==0){int k=0;while(vis[k]) k++;vis[k]=1;dfs(t[k],strlen+1,k+1,len,maxlen);vis[k]=0;return;}for(int i=index;i<maxlen;i++){if(vis[i]==0){if(cur_len+t[i]<=len){if(!vis[i-1] && t[i] == t[i-1]) continue; vis[i]=1;dfs(cur_len+t[i],strlen+1,index+1,len,maxlen);vis[i]=0;}}}}int main(){int T=0;//小木条while(cin>>T&&T!=0){int sum=0;flag=false;for(int i=0;i<T;i++) //输入数据{cin>>t[i];    sum+=t[i];   }sort(t,t+T,cmp);    //排序int i;for(i=t[0];i<sum;i++) { if(sum%i==0) //从小到大遍历每个约数 { memset(vis,0,sizeof(vis)); dfs(0,0,0,i,T);  //判断是否可以凑出这个长度 if(flag) break;  } } cout<<i<<endl;} return 0;}