poj1011 stick(搜索,剪枝)

来源:互联网 发布:温泽三坐标编程视频 编辑:程序博客网 时间:2024/06/04 23:19

Sticks
Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 115234 Accepted: 26486

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

Sample Output

65

题意十分简单,就是现在有许多不同长度的小木棍,要求用这些小木棍拼成一些长度相等的木棍,问拼成的木棍最短长度是多少。

很明显这是一道搜索题,而且是深度搜索的题目。

第一次,稍微剪了一下枝,TLE!!

第二次,又剪了一下枝,还是TLE!!

第三次,TEL!!

……

中间就不说了,最后终于A了。。。。

这道题的经典之处就是在于它的剪枝技巧。

剪枝一:这也是最容易想到的,就是拼成的木棍的长度一定介于最长的小木棍与所有小木棍长度和之间。

剪枝二:将所有的小木棍降序排序,也可以提高效率,因为越长的木棍越不灵活。

剪枝三:拼成的木棍长度一定是木棍和的因子。

剪枝四:如果在搜索第i根小木棍时没有成功,那么第i+1根小木棍如果与i根长度相同也不可能成功。

剪枝五(关键):在没有这个剪枝之前一直超时,但是有了这个剪枝之后,立刻降到16ms。

在拼接新的一根木棍时,如果取出的第一根(可以是任意一根)小木棍无法拼接成功,那么此状态不可能拼接成功,因为子状态失败,总状态不可能成功。所以直接返回上一步的拼接。

剪枝六(关键):与剪枝五相似,如果剩下的木棍长度,刚好等于完成此次拼接的长度,并且没能完成全部拼接,那么当前状态不可能成功。返回上一步的拼接。


剪枝五和剪枝六可能有点难以理解,我的表述也有些不清楚。其实自己多想想就就好了,我也是想了一段时间才把它弄明白。


#include<stdio.h>int stick[70];int vis[70]={0};int ans,end,n;int cmp(int *a,int *b){    return *b-*a;}void dfs(int len,int num,int now,int lv){    int i;    if(ans==1||lv==end) {ans=1;return;}    for(i=num;i<n;i++)    {        if(vis[i])            continue;        if(!vis[i]&&!vis[i-1]&&stick[i]==stick[i-1]) //剪枝四            continue;        vis[i]=1;                if(now+stick[i]<len)            dfs(len,i,now+stick[i],lv);        else if(now+stick[i]==len)            dfs(len,0,0,lv+1);                    vis[i]=0;        if(now==0) break;  //剪枝五        if(now+stick[i]==len) break;  //剪枝六    }}int main(){    int i,sum,max;    while(scanf("%d",&n)&&n)    {        for(i=0,sum=0,max=0;i<n;i++)        {            vis[i]=0;            scanf("%d",&stick[i]);            sum+=stick[i];            if(stick[i]>max) max=stick[i];  // 剪枝一        }        qsort(stick,n,sizeof(stick[0]),cmp); //剪枝二        for(i=max,ans=0;i<=sum;i++)  // 剪枝三        {            if(sum%i==0)            {                end=sum/i;                dfs(i,0,0,0);                if(ans)                {                    printf("%d\n",i);                    break;                }            }        }    }    return 0;}


0 0
原创粉丝点击