POJ 1011 Sticks(深搜+剪枝)

来源:互联网 发布:个人理财软件 编辑:程序博客网 时间:2024/05/21 17:51

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

9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0
Sample Output

6
5

题目大意
给定一定数量和长度的木棍,拼接成任意个新的相同长度的木条,木棍不能有剩余,求可以拼接的木条的最短长度。

解题思路
1、从小到大枚举所能拼接的木条的长度,直到满足条件输出结果。枚举的范围是[木棍长度的最大值,木棍长度的总和];
2、局部贪心:因为越长的木棍对后面木棍的约束力越大,因此对小木棍进行排序,由大到小搜索,这样就可以在尽可能靠近根的地方进行剪枝;
PS:否定纯粹贪心策略:示例10 21 14 13 11 9 6 4 3 2 1,若完全使用贪心策略,则拼接顺序为{21},{14,6,1},{13,4,3,*},此时1已被上次使用,所以拼接21失败。但存在另一种情况满足这个长度即{21},{14,4,3},{13,6,2},{11,9,1}。
3、剪枝思想:
(1)当使用某个长度的木棍深搜完之后发现并不能拼接成目标长度的,木条,则代表该长度的木棍对于当前所拼接木条而言不可行,则之后再存在相同长度的木棍,直接跳过;
(2)在取组合成某个 len(len2) 值木条的第一个木棍时,假如为st[i],如果递归回来发现不可行(即递归回来发现当前所拼接木条的长度仍为0),则剪枝退出当前木条的搜索,直接返回到上一个 len(len1) 值木条搜索的末端,尝试替换其他木棍来拼接。如果不直接返回当前的搜索,因为 st[i] 无法与其他木棍组合成当前的 len(len2)值,则在继续搜索的过程中,也肯定会再次使用到 st[i],同样不会满足条件,所以直接退出,进行剪枝。

代码实现

#include <iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define maxn 70int N,len;bool flag;int st[maxn],visit[maxn];bool cmp(int a,int b){    return a>b;}void dfs(int num,int total,int index)  //还需拼成的木条的个数、当前正在拼接木条已有的长度、使用的木棍的序号{    if(flag) return ;    if(num==0)    {        flag=true;    }    int lastst=-1;  //标记上次使用的木棍的长度    for(int i=index; i<N; i++)    {        if(!visit[i]&&st[i]!=lastst)   //剪枝1        {            lastst=st[i];            if(total+st[i]<len)            {                visit[i]=1;                dfs(num,total+st[i],i+1);    //剪枝2                if(flag) return ;                visit[i]=0;                if(total==0) return ;               }            else if(total+st[i]==len)            {                visit[i]=1;                dfs(num-1,0,0);                if(flag) return ;                visit[i]=0;                if(total==0) return ;            }        }    }}int main(){    int sum;    while(~scanf("%d",&N))    {        sum=0;        memset(visit,0,sizeof(visit));        if(N==0) break;        for(int i=0; i<N; i++)        {            scanf("%d",&st[i]);            sum+=st[i];        }        sort(st,st+N,cmp);        int t=0;        for(len=st[0]; len<=sum; len++)        {            memset(visit,false,sizeof(visit));            flag=false;            if(sum%len==0)            {                int num=sum/len;                dfs(num,0,0);                if(flag)                {                    printf("%d\n",len);                    break;                }            }        }    }    return 0;}
1 0
原创粉丝点击