zoukankan      html  css  js  c++  java
  • 理解回溯法及例题分析

    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 

  • 相关阅读:
    ubuntu 安装 redis desktop manager
    ubuntu 升级内核
    Ubuntu 内核升级,导致无法正常启动
    spring mvc 上传文件,但是接收到文件后发现文件变大,且文件打不开(multipartfile)
    angular5 open modal
    POJ 1426 Find the Multiple(二维DP)
    POJ 3093 Margritas
    POJ 3260 The Fewest Coins
    POJ 1837 Balance(二维DP)
    POJ 1337 A Lazy Worker
  • 原文地址:https://www.cnblogs.com/CYUCHUN/p/10163128.html
Copyright © 2011-2022 走看看