`

回溯法

阅读更多

原文:http://leihong511.blog.163.com/blog/static/47256469200962353650348/

如果上期的“百钱买百鸡”中鸡的种类数是变化的,用枚举法就无能为力了,这里介绍另一种算法——回溯法。

回溯法是一种既带有系统性又带有跳跃性的搜索法,它的基本思想是:在搜索过程中,当探索到某一步时,发现原先的选择达不到目标,就退回到上一步重新选择。它主要用来解决一些要经过许多步骤才能完成的,而每个步骤都有若干种可能的分支,为了完成这一过程,需要遵守某些规则,但这些规则又无法用数学公式来描述的一类问题。下面通过实例来了解回溯法的思想及其在计算机上实现的基本方法。

例1、从N个自然数(1,2,…,n)中选出r个数的所有组合。

算法分析:设这r个数为a1,a2,…ar,把它们从大到小排列,则满足:

(1)    a1>a2>…>ar;

(2)    其中第i位数(1<=i<=r)满足ai>r-i;

我们按以上原则先确定第一个数,再逐位生成所有的r个数,如果当前数符合要求,则添加下一个数;否则返回到上一个数,改变上一个数的值再判断是否符合要求,如果符合要求,则继续添加下一个数,否则返回到上一个数,改变上一个数的值……按此规则不断循环搜索,直到找出r个数的组合,这种求解方法就是回溯法。

如果按以上方法生成了第i位数ai,下一步的的处理为:

(1)    若ai>r-i且i=r,则输出这r个数并改变ai的值:ai=ai-1;

(2)    若ai>r-i且i≠r,则继续生成下一位ai+1=ai-1;

(3)    若ai<=r-i,则回溯到上一位,改变上一位数的值:ai-1=ai-1-1;

算法实现步骤:

第一步:输入n,r的值,并初始化;  i:=1;a[1]:=n;

第二步:若a[1]>r-1则重复:

若a[i]>r-i,①若i=r,则输出解,并且a[i]:=a[i]-1;

②若i<>r,则继续生成下一位:a[i+1]:=a[i]-1; i:=i+1;

若 a[i]<=r-i,则回溯:i:=i-1; a[i]:=a[i]-1;

第三步:结束;

程序实现

var  n,r,i,j:integer;

 a:array[1..10] of integer;

begin

  readln(n,r);i:=1;a[1]:=n;

  repeat

    if  a[i]>r-i  then {符合条件 }

      if i=r  then  {输出}

begin

for j:=1 to r do write(a[j]:3);

writeln;

        a[i]:=a[i]-1;

      end

else {继续搜索}

begin a[i+1]:=a[i]-1; i:=i+1;end

    else{回溯}

      begin  i:=i-1; a[i]:=a[i]-1;end;

  until  a[1]=r-1;

end.

下面我们再通过另一个例子看看回溯在信息学奥赛中的应用。

例2 数的划分(noip2001tg)

问题描述 整数n分成k份,且每份不能为空,任意两份不能相同(不考虑顺序)。

例如:n=7,k=3,下面三种分法被认为是相同的。

1,1,5;    1,5,1;    5,1,1;

问有多少种不同的分法。

输入:n,k      (6<n<=200,2<=k<=6)

输出:一个整数,即不同的分法。

样例

输入:  7   3

输出:4   {四种分法为:1,1,5; 1,2,4; 1,3,3; 2,2,3;}

算法分析:此题可以用回溯法求解,设自然数n拆分为a1,a2,…,ak,必须满足以下两个条件:

(1)    n=a1+a2+…+ak  ;

(2)    a1<=a2<=…<=ak  (避免重复计算);

现假设己求得的拆分数为a1,a2,…ai,且都满足以上两个条件,设sum=n-a1-a2-…-ai,我们根据不同的情形进行处理:

(1)    如果i=k,则得到一个解,则计数器t加1,并回溯到上一步,改变ai-1的值;

(2)    如果i<k且sum>=ai,则添加下一个元素ai+1;

(3)    如果i<k且sum<ai,则说明达不到目标,回溯到上一步,改变ai-1的值;

算法实现步骤如下:

第一步:输入自然数n,k并初始化;t:=0; i:=1;a[i]:=1; sum:=n-1; nk:=n div k;

第二步:如果a[1]<=nk 重复:

若i=k,搜索到一个解,计数器t=t+1;并回溯;

否则:①若sum>=a[i]则继续搜索;

②若sum<a[i]则回溯;

搜索时,inc(i);a[i]:=a[i-1];sum:=sum-a[i];

回溯时,dec(i); inc(a[i]); sum:=sum+a[i+1]-1;

第三步:输出。

程序如下:

var

  n,nk,sum,i,k:integer;

  t:longint;

  a:array[1..6]of integer;

begin

  readln(n,k);

  nk:=n div k;

  t:=0; i:=1;a[i]:=1; sum:=n-1;{初始化}

  repeat

if i=k then{判断是否搜索到底}

begin  inc(t); dec(i);inc(a[i]); sum:=sum+a[i+1]-1; end {回溯}

    else begin

if sum>=a[i] then {判断是否回溯}

begin inc(i);a[i]:=a[i-1];sum:=sum-a[i];end{继续搜}

      else begin dec(i); inc(a[i]); sum:=sum+a[i+1]-1; end;{回溯}

    end;

  until a[1]>nk;

  writeln(t);

end.

 

回溯法是通过尝试和纠正错误来寻找答案,是一种通用解题法,在NOIP中有许多涉及搜索问题的题目都可以用回溯法来求解
分享到:
评论

相关推荐

    常见回溯法问题解决方案

    回溯法是一种在尝试解决问题时,通过试探性地做出选择并逐步构造可能的解,当发现当前选择不能导致有效解时,就撤销该选择并尝试其他路径的搜索算法。它通常用于解决组合优化问题,如圆排列问题、装载问题等。在本...

    回溯法(ACM程序设计,算法竞赛)

    回溯法是一种重要的算法策略,尤其在解决计算机科学中的优化问题和搜索问题时十分常见,如ACM程序设计和算法竞赛中就常常被用到。它通常用于在约束条件下寻找问题的所有解或某个最优解。回溯法的核心思想是通过试探...

    批处理作业调度回溯法java实现

    批处理作业调度回溯法java实现 批处理作业调度回溯法是一种解决作业调度问题的算法,它通过回溯法来搜索所有可能的解决方案,以找到最佳的作业调度方式。在这个Java实现的批处理作业调度程序中,我们使用回溯法来...

    回溯法实验报告

    【回溯法实验报告】 本实验报告主要围绕回溯法这一算法进行,旨在深入理解和掌握回溯法的基本思想和应用。回溯法是一种基于试探性的解决问题的算法,它通过逐步构造可能的解并检查这些解的合法性来寻找问题的正确...

    哈密顿回路 回溯法——C++代码

    在这个“哈密顿回路 回溯法——C++代码”的项目中,我们看到的是使用C++编程语言来实现的回溯法求解哈密顿回路。C语言和C++虽然在语法上有一定差异,但C++是在C语言基础上发展起来的,因此,此处的描述中提到的...

    n后问题---递归回溯法 n后问题---递归回溯法

    n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---...

    回溯法01背包

    回溯法是一种在解决问题时通过试探性地做出选择并逐步构造解决方案的方法,如果发现当前选择无法得到有效的解,则撤销该选择,尝试其他可能的选择,这一过程就像沿着一条路径探索直至找到答案或者证明无解,然后返回...

    批处理作业调度问题 回溯法——C++代码

    在这个场景中,回溯法是一种常用的解决策略,它是一种试探性的解决问题的方法,通过尝试所有可能的解决方案并逐步构建答案,当发现当前路径无法导出有效解时,会撤销最近的选择,退回一步重新尝试其他路径。...

    回溯法实验报告解装载问题

    回溯法是一种基于试探性的深度优先搜索的算法,常用于解决约束满足问题。在这个实验报告中,回溯法被应用于解决装载问题,具体是经典的N皇后问题,即在N×N的棋盘上放置N个皇后,使得每行、每列以及对角线上的皇后...

    Python基于回溯法解决01背包问题实例

    这个问题可以通过多种方法解决,其中回溯法是一种常用的算法策略。 回溯法是一种通过深度优先搜索解决问题的算法,它尝试构建解决方案的候选树,并在发现无法找到有效解时撤销最近的选择,返回上一层继续探索其他...

    回溯法求解子集和问题

    回溯法是一种强大的算法策略,常用于解决组合优化问题,如子集和问题。这个问题的目标是从给定的一组整数中找出所有可能的子集,使得这些子集的元素和等于一个特定的目标值。在本案例中,我们将深入探讨如何使用回溯...

    0-1背包的回溯法求解

    在0-1背包问题中,回溯法通过构建所有可能的物品选取组合,并在过程中不断剪枝,避免无效的搜索,来寻找最优解。 以下是0-1背包问题回溯法求解的详细步骤: 1. **定义状态**:通常用一个二维数组`dp[i][w]`表示前i...

    实验四 用回溯法求解跳马问题.zip

    标题中的“实验四 用回溯法求解跳马问题”是一个典型的计算机科学与编程相关的课题,主要涉及的问题是利用回溯法解决棋盘游戏中的马的移动路径问题。回溯法是一种通过试探性的解决问题的方法,当遇到不符合条件的...

    回溯法解数独问题

    ### 回溯法解数独问题 #### 一、数独简介 数独是一种起源于18世纪瑞士的数字逻辑游戏,它不仅是一项娱乐活动,也是一种极佳的智力锻炼工具。标准的数独由9个3×3的小方格组成的大九宫格构成,共计81个格子。游戏...

    圆排列问题-回溯法-排列集

    圆排列问题-回溯法-排列集 圆排列问题是一种经典的NP难问题,它是指在一个圆形的排列中,找到一个最佳的排列,使得圆形的总长度最小。这是一个非常复杂的问题,需要使用高级的算法来解决。在这个问题中,我们使用的...

    回溯法解决数独问题-2.docx

    回溯法是一种通过递归试错来寻找问题所有解决方案的算法,它的基本思想是:在尝试解决一个问题时,如果发现已不满足求解条件,就回退到上一步或上几步重新尝试其他可能的解,直到找到所有正确解或确定无解为止。...

    用回溯法解决01背包问题C语言实现

    回溯法是一种试探性的解决问题的方法,通过尝试所有可能的解决方案,并在不合适时撤销上一步操作,从而避免无效的搜索。在01背包问题中,回溯法可以用来枚举所有可能的物品选取状态,找到最优解。 以下是使用C语言...

Global site tag (gtag.js) - Google Analytics