POJ-1011-Sticks (dfs深搜+剪枝)

版权声明:欢迎评论与转载,转载时请注明出处! https://blog.csdn.net/wjl_zyl_1314/article/details/84303950

原题链接:
http://poj.org/problem?id=1011
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
题意:
有n个木棍,每一个木棍都有自己的长度(大于0的整数),这些木棍是由一些长度相同的木棍裁断形成的,现在要求找出满足题意的原有木棍的最小长度。
题意:
一开始,想用二分,但发现最终还是要搜索,所以就直接枚举长度搜索了。
dfs搜索部分,如果当前木棍可以拼接成一个长度合理的木棍的话,继续深搜,如果不能则应该继续搜索所有木棍看能否组成长度合理的木棍,直到恰好可以拼成应有的木棍数。
剪枝:
如果长度总和必须是单一木棍长度的倍数,搜索时,如果该长度不能满足条件,则可以直接跳过该长度的木棍。
(更多细节见代码)
附上AC代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int n,st[65];
int sum,num,len;//sum记录所有木棍的总长度,len记录最小的满足题意的长度,num记录在某一个长度len下木棍总数
bool vis[65];
bool cmp(int a,int b)//定义排序方式
{
    return a>b;
}

bool dfs(int s,int l,int pos)//s:已组成木棍的个数,l当前木棍的长度,pos:开始拼接木棍的位置
{
    bool flag = (l == 0?true:false);
    if(s==num)return true;
    for(int i = pos + 1;i <=n;i++)
    {
        if(vis[i])continue;
        if(l + st[i]==len)//可以拼接成len的长度
        {
            vis[i] = true;
            if(dfs(s+1,0,0))//继续深搜
            return true;
            vis[i] = false;
            return false;
        }
        else if(l + st[i]<len)//与第i个木棍拼接起来不够len长
        {
            vis[i] = true;
            if(dfs(s,l+st[i],i))//继续深搜
            return true;
            vis[i] = false;
            if(flag)return false;//如果当前木棍长度为0,也就是当前的这跟木棍无法组成一根长度为len的情况
            while(st[i]==st[i+1])i++;//不对于相同长度的来拼接,合理剪枝
        }
    }
    return false;
}
int main()
{
    while(scanf("%d",&n)!=EOF,n)
    {
        sum=0;
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&st[i]);
            sum+=st[i];
        }
        sort(st+1,st+n+1,cmp);//从大到小排序
        for(len=st[1];len<=sum;len++)//len所有可能的范围
        {
            if(sum%len==0)//总长度sum必须是len的倍数
            {
                num=sum/len;
                memset(vis,false,sizeof(vis));//重置
                if(dfs(1,0,0))//满足题意,输出最小值
                {
                    printf("%d\n",len);
                    break;
                }
            }
        }
    }
    return 0;
}

欢迎评论!

猜你喜欢

转载自blog.csdn.net/wjl_zyl_1314/article/details/84303950