• 深搜的剪枝技巧(一)——树的划分(可行性剪枝、上下界剪枝)


    本系列的开篇之作,先介绍一下剪枝的概念

    一、什么是剪枝

    • 搜索的进程可以看成是从树根出发,遍历一颗倒置的树——搜索树的过程。剪枝就是通过某种判断,避免一些不必要的遍历过程

    二、剪枝的原则

    • 正确性
    • 准确性
    • 高效性

    三、 深度优先搜索的优化技巧

    • 优化搜索顺序
    • 排除等效冗余
    • 可行性剪枝
    • 最优性剪枝
    • 记忆化

    四、树的划分(可行性剪枝、上下界剪枝)

    • 问题描述——将整数 n 划分成 k 份,且每份不能为空,问有多少种不同的分法?当 n = 7,k = 3 时,下面三种分法被认为是相同的,1,1,5;1,5,1;5,1,1。

    • 输入格式——输入文件只有一行,为两个整数 n 和 k((6 < n leq 200,2 leq k leq 6))

    • 输出格式——输出文件只有一行,为一个整数,即不同的分法数

    • 样例输入

      7 3
      
    • 样例输出

      4
      
    • 样例解释—— 4 种分法为 1,1,5;1,2,4;1,3,3;2,2,3

    • 思路分析——将数字 n 划分成 k 份,就是求 (x_1 + x_2+...+x_k = n) 方程的解,依次枚举 (x_1到x_k) 的值,然后判断

    • 剪枝分析

      • 由于分解数不考虑顺序,因此设定分解数依次递增,所以扩展结点时的“下届”应是不小于前一个扩展结点的值,即 (a[i-1] leq a[i])
      • 假设我们将 n 已经分解成了 (a[1] + a[2]+ ...+a[i-1]),则 (a[i]) 的最大值为将 i~k 这 k-i+1 份平均划分,即设 (m = n-(a[1]+a[2]+...+a[i-1])),则 (a[i]leq m/(k-i+1)),所以扩展结点的“上届”是 (frac{m}{k-i+1})
    • 代码:

      #include <iostream>
      
      using namespace std;
      
      int n,m,a[8],s= 0;
      
      void Solve(int k);
      
      int main()
      {
          cin>>n>>m;
          a[0] = 1;
          Solve(1);
          cout<<s<<endl;
          return 0;
      }
      void Solve(int k)
      {
          if(n == 0)
              return;
          if(k == m)
          {
              if(n >= a[k-1])
                  s++;
              return;
          }
          for(int i = a[k-1];i<=n/(m-k+1);i++)
          {
              a[k] = i;
              n -= i;
              Solve(k+1);
              n += i;
          }
      }
      
  • 相关阅读:
    [原创]Windows 7 下成功添加网络共享HP打印机
    [原创]PDFCreator自动保存及文件名带空格、后缀名丢失的解决方法(Windows 7通过)
    [原创]U872客户端“system.net.sockets.socketexception”的解决方法
    [转载]Windows 7默认共享无法访问
    [转载]使Excel不显示0值的三招
    [原创]使用空密码远程桌面连接
    分布式架构理论
    ffmpeg重要函数和结构体整理
    es~存储部分字段
    es~text与keyword的选择
  • 原文地址:https://www.cnblogs.com/NikkiNikita/p/9468138.html
Copyright © 2020-2023  润新知