poj1011木棒问题<深度优先搜索>_看在眼里_百度空间

题意:

    给出一定数量的小木棒的长度,它是由等长的若干木棒随意砍断所得到的。对于给定的一组小木棒,请求出原始木棒的最小长度。

思路:

        1.看到这个题,就是要把小棒一个个进行比较,看能不能恢复若干个原棒。但这样枚举效率太低。

         2.这里用深度优先搜索来遍历(递归实现)速度较快。

         3.假设原始木棒的长度已定,那么由若干小棒来组成一根这样的棒后,其它的原棒将不再由这些已经用过的小棒来拼接了。我们可以设置visited数组来标记这些已经“成功”拼接的木棒,而不是已经用过的木棒。

         4.那么原始木棒长度有多长,不至于从0一直往后试探吧?这样太麻烦。因为长度最小的原棒,它的长度不会比目前{zd0}的小棒还短。长度{zd0}的原棒的长度不会比所有小棒的长度和还长。这样范围就确定了。

         5.我们用深搜用什么参数呢?

                    首先应该是对某个可能存在的长度(原棒长)进行试探性的验证,看是否能由这所有的小棒组成。那么这个参数是必须的,记为len。

                    然后,每当“成功”接收一根小木棒(前提是这根小木棒的接收能导致一根完整的木棒被拼出,而不是暂时被接收),那么可用的小木棒数就会相应减1.这个参数很重要(记为num)。

                    再就是对我们要试探的原木棒可能取值,每当它成功接收一根小木棒,还需要用来拼接一根原木棒的长度就会减小。这也是搜索过程必须知道的量,当它减小到0时,说明一根原木棒拼接完成,它将重新被赋值为len,从而进行下一根木棒的搜索。可知这个参数同样很重要(记为remains_len)。

        6.由于过程中要确定某根小棒是否确定成功被接收,它就得提前预知加入这根小棒后其它的小木棒能不能匹配成功,就叫要求在遍历某个小木棒时,对其后的木棒进行递归搜索(深搜的特点),若能匹配成功,则标记当前小木棒为用过,可以直接返回(试探成功);若不能匹配,说明此棒目前不可用,将标记取消,待下一次搜索用。若当前木棒不可用,那么与这根小木棒长度相同的木棒也将不可用,直接跳过(剪枝),而且若这个小木棒的长度刚好是reamins_len的长度,那么更能说明后面的不能匹配了,因为如此合适的小棒被接收都不能导至试探成功,后面的小棒更不可能,直接返回0(试探失败 )(剪枝)。还有就是如果len=remains_len(说明这是新一根原棒,还没有进行匹配),而在预先判断匹配与否时已经判断不能匹配,这样都不能匹配,那么说明以后都不能匹配了(这就是深搜的效果了)。返回0(试探失败)(剪枝)。

       7.当remains_len=0&&num=0说明能用的棒已经没有,而且拼成一根原棒还需的长度为0,只能表示原棒已经完整的由这所有的小棒拼接出来。此时只需返回len(试探成功),这个操作应该放在函数最前。

      8.如果深搜完成,仍未返回试探成功,到了函数的{zh1},只能说明这个试探失败。直接返回0.

      9.为了让用过但没有被成功接收的小木棒再次利用,所以函数里对每个小棒进行一次搜索。以让这些漏网的小木棒或许能被再次利用。

      10.注意:当换一个原木棒长度进行试探时,要置visited为0,否则会与上次搜索混在一起

我的源程序:

#include"iostream"
//#include"stdlib.h"
using namespace std;
int a[69];//存小棒长大小{zh0}大于64
int visited[69];//标记小棒是否被用
int n;//小棒个数
int cmp(const void *a,const void *b)
{
    return *(int*)b-*(int*)a;
}
/*DFS:递归搜索,以剩下小棒数和拼接一根棒所需长度作为递归参数*/
int DFS(int len,int remains_len,int num)/*作为搜索的棒长len,拼成len长的棒还需的长度remains_len,剩下的未作为拼接的小棒个数*/
{
    if(remains_len==0&&num==0)/*当还需长度为0且未作接接的小棒个数为0时,说明拼接成功*/
    return len;
    if(remains_len==0)/*当完成拼接一个棒时,要重新进行下一根木棒拼接,给remains_len重新赋值*/
    remains_len=len;
    for(int i=0;i<n;i++)
    {
            if(visited[i]==1)/*已经作为成功拼接的小棒,不再作为拼接对象*/
            continue;
            if(remains_len>=a[i])
            {
                 visited[i]=1;/*暂时标记为已经用了*/
                 if(DFS(len,remains_len-a[i],num-1))/*当接受这根小棒a[i],能完成所有任务,则返回成功拼接棒长*/
                 return len;
                 visited[i]=0;/*当用a[i]不能完成任务就不用此棒,将其标记为该步未用此棒*/
                 if(a[i]==remains_len||len==remains_len)/*a[i]=remains_len或remians_len=len时本来表示即将拼成一根棒,或刚进行新一轮拼接但经过上面的if判断,它不能完成所有任务,
                 那么以后的棒不能完成任务,不再考虑,搜索失败(剪枝)*/
                 break;
                 if(a[i]==a[i+1])//当a[i]不能完成任务,与它相同的小棒也不能完成任务(剪枝)
                 i++;
            }
    }
    return 0;
}
int main()
{
    while(cin>>n&&n)
    {
                    int sum=0;//所有小棒长度
                    int len,k;
                    for(int i=0;i<n;i++)
                    {
                            cin>>a[i];
                            sum+=a[i];
                    }
                    qsort(a,n,sizeof(int),cmp);
                    for(len=a[0];len<=sum;len++)
                    {
                        memset(visited,0,sizeof(visited));/*每次尝试都要置所有小棒为可用*/
                        if(sum%len==0)
                        {
                                     k=DFS(len,0,n);
                                      if(k)
                                        break;
                        }
                    }
                    cout<<k<<endl;
    }
    return 0;
}



郑重声明:资讯 【poj1011木棒问题<深度优先搜索>_看在眼里_百度空间】由 发布,版权归原作者及其所在单位,其原创性以及文中陈述文字和内容未经(企业库qiyeku.com)证实,请读者仅作参考,并请自行核实相关内容。若本文有侵犯到您的版权, 请你提供相关证明及申请并与我们联系(qiyeku # qq.com)或【在线投诉】,我们审核后将会尽快处理。
—— 相关资讯 ——