• 理解回溯法及例题分析


    1、对回溯算法的理解

    回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为"回溯点"。

    (1)回溯法解题时通常包含3个步骤:

    ①针对所给问题,定义问题的解空间;

    ② 确定易于搜索的解空间结构;

    ③以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。

    (2)回溯法的算法框架

    ①解空间:问题的解空间至少包含问题的一个(最优)解。其表示形式一般是解空间树:子集树和排列树

    ②递归回溯:

     1 void Backtrack(int t)
     2 {
     3     if(t>n) Output(x);
     4     else {
     5         for(int i=f(n,t);i<=g(n,t);i++) {
     6             x[t]=h(i);
     7             if(Constraint(t)&&Bound(t)) Backtrack(t+1);
     8         }
     9     }
    10 }

    ③迭代回溯:

     1 void IterativeBacktrack(void)
     2 {
     3     int t=1;
     4     while(t>0) {
     5         if(f(n,t)<=g(n,t)) {
     6             for(int i=f(n,t);i<=g(n,t);i++) {
     7                 x[t]=h(i);
     8                 if(Constraint(t)&&Bound(t)) {
     9                     if(Solution(t)) Output(x);
    10                     else t++;
    11                 }
    12             }
    13         }
    14         else t--;          
    15     }
    16 }

    2、例题:子集和问题

    (1)子集和问题

    设集合S={x1,x2,…,xn}是一个正整数集合,c是一个正整数,子集和问题判定是否存在S的一个子集S1,使S1中的元素之和为c。试设计一个解子集和问题的回溯法。

    输入格式:输入数据第1行有2个正整数n和c,n表示S的大小,c是子集和的目标值。接下来的1行中,有n个正整数,表示集合S中的元素。

    输出格式:输出子集和问题的解,以空格分隔,最后一个输出的后面有空格。当问题无解时,输出“No Solution!”。

    输入样例:5 10

                      2 2 6 5 4

    输出样例:2 2 6

    (2)解空间

    本题的解空间为:{x1,x2,x3,x4,···,xn},其中xi表示是否加上第i个数

    (3)约束函数

    本题的约束方式有两部分,①isC + num[i] <= c,通过判断当前子集和是否超出题目要求的子集和来剪枝

    ②isC+total >= c,与第一部分类似

    (4)具体代码

     1 #include <iostream>
     2 using namespace std;
     3 #define N 1000
     4 int n,c,total=0;  // total表示所有整数之和
     5 int isSelect[N]={0};  // 表示整数n是否被选择,1表示选择
     6 int num[N];  // 表示整数集
     7 int isC=0;  // 表示当前子集和
     8 
     9 bool sum(int i)
    10 {
    11     if(isC == c) return true;  // 当子集和符合条件时返回
    12     if(i > n) return false;
    13     total-=num[i];
    14     if(isC + num[i] <= c) {
    15         isSelect[i]=1;
    16         isC+=num[i];
    17         if(sum(i+1)) return true;
    18         isC-=num[i];  // 回溯法
    19     }
    20     if(isC+total >= c) {
    21         isSelect[i]=0;  // 回溯法
    22         if(sum(i+1)) return true;
    23     }
    24     total += num[i];  // 回溯法
    25     return false;
    26 }
    27 
    28 int main()
    29 {
    30     cin>>n>>c;
    31     for(int i=1;i<=n;i++) {
    32         cin>>num[i];
    33         total+=num[i];
    34     }
    35     if(!sum(1)) cout<<"No Solution!";  // 无解时
    36     else {
    37         for(int i=1;i<=n;i++) {
    38             if(isSelect[i]) cout<<num[i]<<" ";
    39         }
    40     }
    41     return 0;
    42 } 

    3、在本章学习过程中遇到的问题及结对编程的情况

     对于回溯法的概念,结合解空间树,理解起来不是很难,但是在代码实践时,有时候会出现不是很明白为什么要怎么写代码的情况,结对小伙伴也不是很明白,总体上还可以,但是还需要多实践多理解。

    参考资料:https://baike.so.com/doc/6735197-6949574.html 

  • 相关阅读:
    Struts2 文件上传和下载
    Struts2的验证框架简单吗?
    Struts2防止重复提交
    Struts2的标签三大类是什么?
    Struts2的值栈和OGNL牛逼啊
    Struts2牛逼的拦截器,卧槽这才是最牛的核心!
    转载---C# 递归创建文件夹
    转载---C# 冻结 datagridview的列
    C# base64编码转成图片
    转载---C# 复制文件夹下的(内容)到指定文件夹中
  • 原文地址:https://www.cnblogs.com/CYUCHUN/p/10163128.html
Copyright © 2020-2023  润新知