`

经典问题:木棒(搜索+强力剪枝)

 
阅读更多
木棒
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 95421   Accepted: 21444

Description

乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过5个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棍的长度都用大于零的整数表示。

Input

输入包含多组数据,每组数据包括两行。第一行是一个不超过64的整数,表示砍断之后共有多少节木棍。第二行是截断以后,所得到的各节木棍的长度。在最后一组数据之后,是一个零。

Output

为每组数据,分别输出原始木棒的可能最小长度,每组数据占一行。

Sample Input

9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0

Sample Output

6
5

Source

Translator

北京大学程序设计实习, Xie Di
==================================================================
这曾经是我省的省选题,当初做的时候一直没A,今天刷题库看到了,搜了下相关内容,终于搞懂了~
==================================================================
资料(来自http://blog.163.com/xdu_cfcry/blog/static/1694623032010718274132/):
==================================================================
   经典搜索题,黑书上的剪枝例题。剪枝的空间很大,剪枝前写下朴素的搜索框架(黑字部分),枚举原始木棍的长度及由那些小木棍组合。原始木棍长度一定是小木棍总长度的约数,因此可以减少枚举量。

          越长的木棍对后面木棍的约束力越大,因此要把小木棍排序,按木棍长度从大到小搜索,这样就能在尽可能靠近根的地方剪枝。(剪枝一)

          如果当前木棍能恰好填满一根原始木棍,但因剩余的木棍无法组合出合法解而返回,那么让我们考虑接下来的两种策略,一是用更长的木棍来代替当前木棍,显然这样总长度会超过原始木棍的长度,违法。二是用更短的木棍组合来代替这根木棍,他们的总长恰好是当前木棍的长度,但是由于这些替代木棍在后面的搜索中无法得到合法解,当前木棍也不可能替代这些木棍组合出合法解。因为当前木棍的做的事这些替代木棍也能做到。所以,当出现加上某根木棍恰好能填满一根原始木棍,但由在后面的搜索中失败了,就不必考虑其他木棍了,直接退出当前的枚举。(剪枝二)

         显然最后一根木棍是不必搜索的,因为原始木棍长度是总木棍长度的约数。(算不上剪枝)

         考虑每根原始木棍的第一根木棍,如果当前枚举的木棍长度无法得出合法解,就不必考虑下一根木棍了,当前木棍一定是作为某根原始木棍的第一根木棍的,现在不行,以后也不可能得出合法解。也就是说每根原始木棍的第一根小木棍一定要成功,否则就返回。(剪枝四)

         剩下一个通用的剪枝就是跳过重复长度的木棍,当前木棍跟它后面木棍的无法得出合法解,后面跟它一样长度的木棍也不可能得到合法解,因为后面相同长度木棍能做到的,前面这根木棍也能做到。(剪枝五)

         这样剪枝基本就结束了,我们发现,每种剪枝都只是加了一条语句,但剪枝效果非常明显。uva307题目跟这个一模一样,当时uva的数据规模更强,许多在poj 10+MS的程序在uva 3000MS都跑不出来,当时我的加上这些剪枝,我的程序在uva也能跑出靠前的成绩。  rank:38      time:0.244s

         剪枝要平衡准确性和额外花费的关系,一开始我用上下界剪枝,这个额外花费相当大,每次搜索一根原始木棍都要更新从某根木棍开始到最后一根可用木棍的总长度,对于一般的数据确实能跑的比没加剪枝快,但对苛刻的,第一根木棍总不成功的数据,这个剪枝就成了程序的瓶颈,导致我在poj都超时了,删除后0MS, 汗~~。

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int used[100],len[100],sum,n,Min,s[100];
int find(int p,int rest,int trest)
{
    int i;
    if (trest==Min) return 1;
    for (i=p;i<=n;i++)
       if (!used[i]&&len[i]<=rest)
       {
          used[i]=1;
          if (len[i]==rest)
          {
             if (find(1,Min,trest-len[i])) return 1;
          } else if (find(i+1,rest-len[i],trest-len[i])) return 1;
          used[i]=0;
          if (len[i]==rest) return 0;
          if (trest==sum) return 0;
          if (rest==Min) return 0;
          while (len[i+1]==len[i]) i++;
       }
    return 0;
}
bool cmp(int a,int b) {return a>b;}
int main()
{
    int i;
    while (scanf("%d",&n)&&n!=0)
    {
       for (i=1;i<=n;i++)
           scanf("%d",&len[i]);
       memset(used,0,sizeof(used));
       sort(len+1,len+n+1,cmp);
       sum=0;
       for (i=1;i<=n;i++) sum+=len[i];
       Min=len[1];
       while (sum%Min!=0) Min++;
       s[n+1]=0;
       while (find(1,Min,sum)==0)
       {
          Min++;
          while (sum%Min!=0) Min++;
       }
       printf("%d\n",Min);
    }
    return 0;
}

==================================================================
看完这个我终于会了,有些强力剪枝真是想不到啊~
==================================================================
贴个代码:

var
n,m,tot,i:longint;
a:array[1..65] of longint;
v:array[1..65] of boolean;

function dfs(nn,p,k,total:longint):boolean;
var i:longint;
begin
     if nn=0 then exit(true);
     i:=1;
     while i<=n do begin
         if (not v[i])and(a[i]+total<=m) then begin
            v[i]:=true;
            if a[i]+total=m then dfs:=dfs(nn-1,p+1,1,0)
            else dfs:=dfs(nn-1,p,k+1,total+a[i]);
            v[i]:=false;

            if dfs then exit(true);
            if (a[i]+total=m)or(k=1) then exit(false);
            while(i<n)and(a[i+1]=a[i])do inc(i);
         end;
         inc(i);
     end;
     exit(false);
end;

procedure sort(l,r:longint);
var i,j,mid,tmp:longint;
begin
     i:=l; j:=r; mid:=a[(l+r)shr 1];
     repeat
           while a[i]>mid do inc(i);
           while a[j]<mid do dec(j);
           if i<=j then begin
              tmp:=a[i]; a[i]:=a[j]; a[j]:=tmp;
              inc(i); dec(j);
           end;
     until i>j;
     if i<r then sort(i,r);
     if l<j then sort(l,j);
end;

begin
     while true do begin
           readln(n); if n=0 then break;

           tot:=0;
           for i:=1 to n do begin
               read(a[i]);
               inc(tot,a[i]);
           end;

           sort(1,n);
           fillchar(v,sizeof(v),false);
           for m:=a[1] to tot do
               if tot mod m =0 then
               if dfs(n,1,1,0) then begin
                  writeln(m);
                  break;
               end;
     end;
end.

 

转自:

http://blog.csdn.net/w745241408/article/details/7517418

分享到:
评论

相关推荐

    DeepLabV3+模型剪枝实战

    为了解决这个问题,模型剪枝技术应运而生。 模型剪枝是一种优化策略,通过删除对模型预测影响较小的网络权重或连接,来减少模型的参数数量和计算量(MACs,Multiply-Accumulate Operations)。在描述中提到,剪枝...

    随机森林+预剪枝+后剪枝

    预剪枝和后剪枝是决策树优化的两种常见策略,它们在构建决策树模型时起到控制复杂度和防止过拟合的作用。 决策树是一种基于树状结构进行决策的算法,每个内部节点代表一个特征,每个分支代表一个特征值,而叶子节点...

    基于C+++EasyX+剪枝算法的能人机对弈的五子棋游戏设计与实现(源码+文档)-C++-能人机对弈的五子棋游戏.zip

    资源名字:基于C+++EasyX+剪枝算法的能人机对弈的五子棋游戏设计与实现(源码+文档)_C++__能人机对弈的五子棋游戏.zip 资源内容:项目全套源码+完整文档 源码说明: 全部项目源码都是经过测试校正后百分百成功运行...

    POJ3733-Changing Digits【DFS+强剪枝】

    【标题】"POJ3733-Changing Digits【DFS+强剪枝】"是一个来自北京大学在线评测系统POJ的编程题目,该题目主要涉及深度优先搜索(DFS)算法和强剪枝策略。在算法竞赛和编程挑战中,这类问题通常要求参赛者通过编写...

    POJ3373-Changing Digits【DFS+强剪枝】

    标题“POJ3373-Changing Digits【DFS+强剪枝】”涉及的是一个编程竞赛中的问题,这个问题在北大POJ(北京大学在线评测系统)平台上被提出。"Changing Digits"是一个算法挑战,而解决方案是通过深度优先搜索(DFS)...

    POJ3009-Curling 2.0【DFS+Vector+回溯+剪枝】

    北京大学在线编程平台上的POJ3009题目名为"Curling 2.0",它是一道涉及到算法与数据结构的复杂问题,主要考察了参赛者对深度优先搜索(DFS)、向量(Vector)操作、回溯法以及剪枝策略的掌握程度。本题的解决方案...

    用分枝界限 回溯+剪枝 动态规划 解决01背包问题

    问题描述:给定一个容量为C的背包及n个重量为wi,价值 为p1的物品,要求把物品装入背包,是背包的价值最大, 此类问题为背包问题。物品或者装入背包,或者不装入背 包,称之为0/1被包问题 假设xi表示物品i被装入背包...

    0 1 背包问题 分支界限 回溯+剪枝

    问题描述:给定一个容量为C的背包及n个重量为wi,价值为p1的物品,要求把物品装入背包,是背包的价值最大,此类问题为背包问题。物品或者装入背包,或者不装入背包,称之为0/1被包问题 假设xi表示物品i被装入背包的...

    C++实现基于极大极小值算法+AlphaBeta剪枝传统搜索算法的五子棋游戏源码(含前端+后端).zip

    C++实现基于极大极小值算法+AlphaBeta剪枝传统搜索算法的五子棋游戏源码(含前端+后端).zipC++实现基于极大极小值算法+AlphaBeta剪枝传统搜索算法的五子棋游戏源码(含前端+后端).zipC++实现基于极大极小值算法+...

    Chinesechess:中国象棋python实现+ab剪枝+GUI+普通人棋力

    3. **AB剪枝**:在AI领域,AB(Alpha-Beta)剪枝是一种优化Minimax搜索算法的方法,用于减少在决策树中搜索的最佳路径时的计算量。在中国象棋的AI实现中,AB剪枝能帮助计算机更有效地预测对手的可能走法,从而提高...

    机器学习课上决策树小demo决策树+随机森林+预剪枝

    通过jueceshu.py建立一棵决策树,再通过main.py从...参考了一些博客,但是他们的预测函数有点问题,不能采用自己的数据集,于是我改进了一下,条件是:预测样本必须满足样本集包括的前6个特征。也可不以西瓜为数据集。

    基于pytorch实现CNN网络卷积层的通道剪枝实现源码(支持权重2D、3D可视化)+剪枝说明文档.zip

    基于pytorch实现CNN网络卷积层的通道剪枝实现源码(支持权重2D、3D可视化)+剪枝说明文档.zip 【说明】 【1】项目代码完整且功能都验证ok,确保稳定可靠运行后才上传。欢迎下载使用!在使用过程中,如有问题或建议,请...

    yolov8 剪枝源码(集成多种剪枝策略)

    支持以下的剪枝方法,代码一键运行,并配有md文档说明: (1) lamp 剪枝 (2) slimming 剪枝 (3) group slimming 剪枝 (4) group hessian 剪枝 (5) Taylor 剪枝 (6)Regularization 剪枝 等等

    搜索经典问题木棒问题模拟exe

    木棒问题是搜索的一个经典问题。这里有一个模拟在不同剪枝方案下,木棒问题的求解过程,可调整播放速度,便于观看分析,欢迎下载。

    剪枝-yolov3剪枝的实现-附项目源码+剪枝教程.zip

    剪枝_yolov3剪枝的实现_附项目源码+剪枝教程

    Chess:C ++中的Chess AI项目

    - α-β剪枝:为了优化Minimax,引入了α-β剪枝,通过提前排除不可能导致最优解的分支,显著减少搜索空间。 4. **评估函数**: - 评估棋局:AI需要一个评估函数来判断当前棋局对己方的优劣。这可能包括计算棋子...

    yolov5 run + 量化+ 蒸馏+剪枝.zip

    《YOLOv5运行、量化、蒸馏及剪枝在PyTorch中的实践》 YOLOv5,全称为You Only Look Once V5,是一种高效且准确的目标检测模型,广泛应用于计算机视觉领域。该模型以其实时性能和高精度受到研究人员和开发者的喜爱。...

    搜索方法中的剪枝优化

    在搜索方法中,剪枝优化是一种提升算法效率的关键技术,主要应用于解决复杂问题的搜索空间。剪枝通过提前排除那些不可能导致解决方案的分支,从而减少不必要的计算,提高搜索效率。在给定的例子“Betsy的旅行”中,...

    模型剪枝-在Oxford-Hand数据集上对YOLOv3进行模型剪枝-附项目源码+数据集+剪枝权重下载-优质项目实战.zip

    模型剪枝_在Oxford-Hand数据集上对YOLOv3进行模型剪枝_附项目源码+数据集+剪枝权重下载_优质项目实战

    国际象棋:C ++中的国际象棋游戏14

    为了高效地搜索,可以使用剪枝策略,如Alpha-Beta剪枝。 8. **启发式算法**:为了减少搜索空间,通常会使用启发式函数来对局面进行评分,例如考虑棋子价值、控制的棋盘区域、中心控制、国王安全等因素。 9. **用户...

Global site tag (gtag.js) - Google Analytics