算法设计与分析复习--回溯(一)

news2024/11/18 6:03:24

文章目录

  • 上一篇
  • 回溯法性质
  • 子集和问题
  • 装载问题
  • 0-1背包问题
  • 下一篇

上一篇

算法设计与分析复习–贪心(二)

回溯法性质

类似穷举的搜索尝试过程,在搜索尝试过程中寻找问题的解,组织得井井有条(避免遗漏), 高效(剪裁避免不必要搜索)

使用深度优先的搜索策略(DFS + 剪枝)

回溯法的阶梯框架:

  1. 子集树算法框架
  2. 排序树算法框架

在这里插入图片描述
在这里插入图片描述
结点类型:

  1. 活结点:自身已生成但是其儿子还没有全部生成
  2. 拓展结点:正在产生儿子的结点
  3. 死结点:不满足约束或所有儿子已经产生,不能向纵深方向移动

为了避免生成那些不可能产生最优解的问题状态,要不断利用限界函数,处死结点=>剪枝

剪枝策略:

  1. 可行性剪枝,左剪枝
  2. 最优性剪枝,右剪枝
  3. 交换搜索顺序,排序方式变化

解空间类型:

  1. 子集树:所给的问题是从n个元素集合S中找出满足某种性质的子集。
    在这里插入图片描述

  2. 排列数:所给问题是确定n个元素满足某种性质的排列。
    在这里插入图片描述
    采用交换方式实现的全排列(顺序有点问题)

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 10;

int a[N], n;
int path[N];

void dfs(int* ans, int k)
{
    if (k == n - 1){
        for (int i = 0; i < n; i ++)
            printf("%d ", ans[i]);
        puts("");
    }
    
    for (int i = k; i < n; i ++){
        swap(ans[k], ans[i]);
        dfs(ans, k + 1);
        swap(ans[k], ans[i]);
    }
}

int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; i ++) path[i] = i + 1;
    
    dfs(path, 0);
    return 0;
}

在这里插入图片描述
在这里插入图片描述

基于子集树框架的问题求解:

  1. 子集和问题
  2. 装载问题
  3. 0-1背包问题
  4. 图的m着色问题

基于排列树框架的问题求解:

  1. 旅行商问题(TSP)
  2. N皇后问题

子集和问题

问题描述:给定n个不同正实数的集合W = {w(i) | 1 <= i <= n}和一个正整数M, 要求找到子集S使得求和为M。

子集和问题要求出所有可行解

左剪枝:求和不超过M => cw + a[i] <= M
右剪枝:当前已选的价值与剩余的数的价值的和要大于M否则不可能找到 => cw + rw >= M

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 110;

int a[N], n, M, cw, rw;
vector<int> ans;

void dfs(int k)
{
    if (k == n)//根节点是0叶结点就是n
    {
        if (cw == M){
            for(auto i : ans)
                printf("%d ", i);
            puts("");
        }
        return;
    }
    rw -= a[k];
    if (cw + a[k] <= M){//左剪枝条件
        cw += a[k];
        ans.push_back(a[k]);
        dfs(k + 1);//向左走
        ans.pop_back();
        cw -= a[k];
    }
    if(rw + cw >= M)//右剪枝条件
        dfs(k + 1);//向右走
        
    rw += a[k];
}

int main()
{
    scanf("%d%d", &n, &M);
    
    for (int i = 0; i < n; i ++) scanf("%d", &a[i]), rw += a[i];
    
    dfs(0);
    return 0;
}

在这里插入图片描述

装载问题

和贪心中的装载问题不同
问题描述:n个集装箱要装到2艘载重量分别c1,c2的货轮,其中集装箱 i i i 的重量 为 w i w_i wi。要求找到合理的装载方案将这n个货箱装上这2艘轮船。

要使两个船都装上,可以考虑将第一个船尽可能装满,然后将剩下的货物装在第二艘船上,如果没超重就是可行的,将考虑两个船的问题转换成考虑一个。

为找到将左边轮船撞得最满的方案,用bestw进行限界

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 110;

int a[N], n, c1, c2;
int cw, bw, rw, other;
vector<int> ans;

void dfs(int k)
{
    if (k == n){
        bw = cw;
        if(other > c2) return;//other是另一艘船货物重量
        for (auto i : ans)
            printf("%d ", i);
        puts("");
        return;
    }
    
    rw -= a[k];
    if (cw + a[k] <= c1)
    {
        cw += a[k];
        ans.push_back(a[k]);
        dfs(k + 1);
        ans.pop_back();
        cw -= a[k];
    }
    if (cw + rw >= bw){
        other += a[k];
        dfs(k + 1);
        other -= a[k];
    }
    rw += a[k];
    
}

int main()
{
    scanf("%d%d%d", &n, &c1, &c2);
    
    for (int i = 0; i < n; i ++) scanf("%d", &a[i]), rw += a[i];
    
    dfs(0);
    return 0;
}

在这里插入图片描述

0-1背包问题

问题描述:给定n中物品和一个背包。物品 i i i 的重量是 w i w_i wi ,其价格为 v i v_i vi , 背包容量为 c c c 。 问如何选择装入背包中的物品,使得装入背包物品的总价值最大?

左剪枝:满足背包容量即可

右剪枝:右剪枝就是求剩余背包重量rw = c - cw中贪心背包的最优价值,由于允许部分装入,所以一定比0-1背包装的满价值更大,结果是剩余价值的一个上界,允许右剪枝的条件更加宽松。
r v = ∑ v j ( 不超过背包剩余重量的物品价值 ) + ( 背包剩余重量 ) ∗ (不被放入的物品的单位价值)【部分装入的结果】 rv = \sum{v_j}(不超过背包剩余重量的物品价值) + (背包剩余重量) * (不被放入的物品的单位价值)【部分装入的结果】 rv=vj(不超过背包剩余重量的物品价值)+(背包剩余重量)(不被放入的物品的单位价值)【部分装入的结果】
限界函数:
c v + r v > = b v cv + rv >= bv cv+rv>=bv

交换搜索顺序:由于用到了贪心背包,所以按照物品单价从大到小的方式进行搜索。

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
typedef pair<double, double> PII;

const int N = 110;

double w[N], v[N];
int n, c;
double cw, cv, bv;
vector<PII> ob, x;//x用来记录当前的搜索顺序
vector<PII> ans;//最优解,解只有一个,将这个迭代的解记录

bool cmp(PII x, PII y)
{
    return (x.second / x.first) > (y.second / y.first);
}

bool bound(int rw, int k)
{
    int i = k + 1;
    double rv = cv;
    //printf("cv: %.2lf rw: %d\n", cv, rw);
    while(i <= n && ob[i].first <= rw)
    {
        rw -= ob[i].first;
        rv += ob[i].second;
        i ++;
    }
    //printf("比值:%.2lf rw:%d\n", ob[i].second / ob[i].first, rw);
    if (i <= n) rv += (ob[i].second / ob[i].first) * rw;
    //printf("%d = %.2lf\n", k, rv);
    return rv >= bv;
}

void dfs(int k)
{
    if (k == n){
        if (cv > bv){
            bv = cv;//更新最优结果
            ans = x;
        }
        return;
    }
    
    if (cw + ob[k].first <= c)
    {
        cw += ob[k].first;
        x.push_back(ob[k]);
        cv += ob[k].second;
        dfs(k + 1);
        cv -= ob[k].second;
        x.pop_back();
        cw -= ob[k].first;
    }
    if(bound(c - cw, k))
    {
        dfs(k + 1);
    }
}

int main()
{
    scanf("%d%d", &n, &c);
    
    for (int i = 0; i < n; i ++) scanf("%lf", &w[i]);
    for (int i = 0; i < n; i ++) scanf("%lf", &v[i]);
    for (int i = 0; i < n; i ++) ob.push_back({w[i], v[i]});
    
    sort(ob.begin(), ob.end(), cmp);
    
    dfs(0);
    
    puts("对应物品的重量和价值:");
    for (auto i : ans)
        printf("{%d, %d} ", (int)i.first, (int)i.second);
    puts("\n最优价值:");
    printf("%d", (int)bv);
    return 0;
}

在这里插入图片描述
在这里插入图片描述

下一篇

未完待续

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1233741.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

工业领域的设备“监测”和“检测”有何区别?

在工业领域中&#xff0c;设备的监测和检测是关键的运维活动&#xff0c;它们在保障设备可靠性和生产效率方面发挥着重要作用。尽管这两个术语经常被人们混为一谈&#xff0c;但它们在含义和应用上存在一些关键区别。 "监测"与"检测"的概念 1. 监测&#…

PHP手动为第三方类添加composer自动加载

有时候我们要使用的第三方的类库&#xff08;SDK&#xff09;没用用composer封装好&#xff0c;无法用composer进行安装&#xff0c;怎么办呢&#xff1f;&#xff1f;&#xff1f; 步骤如下&#xff1a; 第一步、下载你需要的SDK文件包&#xff0c;把它放在vendor目录下 第二…

【Python】学习Python面向对象编程的疑问

&#xff08;Java菜鸟来学Python了&#xff09; &#x1f914; 1. 静态方法与类方法什么区别&#xff1f; 实例方法只能被实例对象调用(Python3 中&#xff0c;如果类调用实例方法&#xff0c;需要显示的传self, 也就是实例对象自己)&#xff0c;静态方法(由staticmethod装饰…

【MATLAB源码-第84期】基于matlab的802.11a标准的OFDM系统误码仿真对比QPSK,16QAM。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 基于802.11a标准的OFDM&#xff08;正交频分复用&#xff09;系统是一种高效的无线通信技术&#xff0c;特点如下&#xff1a; 频带与信道&#xff1a; 802.11a工作在5 GHz频段&#xff0c;这个频段相对于2.4 GHz&#xff08…

O-Star|再相识

暑去秋来&#xff0c;岁月如梭&#xff0c;几名"O-Star"们已经入职一段时间&#xff0c;在这期间他们褪去青涩&#xff0c;逐渐适应了公司的工作环境和文化&#xff0c;迈向沉稳&#xff5e; 为了进一步加深校招生之间的交流与了解&#xff0c;提高校招生的凝聚力和…

77基于matlab的蚁群优化路径算法,二维路径和三维路径优化

基于matlab的蚁群优化路径算法&#xff0c;二维路径和三维路径优化。输出可视化最优路径和距离迭代曲线。数据可更换自己的&#xff0c;程序已调通&#xff0c;可直接运行。 77三维和二维路径可视化 (xiaohongshu.com)

Docker快速安装Mariadb11.1

MariaDB数据库管理系统是MySQL的一个分支&#xff0c;主要由开源社区在维护&#xff0c;采用GPL授权许可 MariaDB的目的是完全兼容MySQL&#xff0c;包括API和命令行&#xff0c;使之能轻松成为MySQL的代替品。在存储引擎方面&#xff0c;使用XtraDB来代替MySQL的InnoDB。 Mari…

第2关:图的深度优先遍历

任务要求参考答案评论2 任务描述相关知识编程要求测试说明 任务描述 本关任务&#xff1a;以邻接矩阵存储图&#xff0c;要求编写程序实现图的深度优先遍历。 相关知识 图的深度优先遍历类似于树的先序遍历, 是树的先序遍历的推广&#xff0c;其基本思想如下&#xff1a; …

如何利用CHATGPT写主题文章

问CHAT&#xff1a;新课标下畅言智慧课堂助力小学生量感培养&#xff0c;拟解决的关键问题 CHAT回复&#xff1a; 1. 确定智慧课堂在新课标下的正确应用方法&#xff1a;新课标对教育方法、内容等提出了新的要求&#xff0c;需要探讨如何将智慧课堂与新课标相结合&#xff0c;…

Rockchip Clock

一:概述 1、时钟子系统 本章节所指的时钟是给SOC各个组件提供时钟的树状框架,而非内核使用的时钟。和其他模块一样,CLOCK也有框架,用以适配不同的平台。适配层之上是客户代码和接口,也就是各模块(如需要时钟信号的外设)的驱动。适配层之下是具体的SOC的时钟操作细节。…

宏电股份荣膺国家知识产权优势企业称号,科技创新与研发实力获国家级认可

近日&#xff0c;国家知识产权局公布了2023年度国家知识产权优势企业的评审结果&#xff0c;宏电股份凭借强大的技术实力和创新能力&#xff0c;荣获“国家知识产权优势企业”荣誉称号。这一荣誉是对宏电股份在技术创新和知识产权创造、运用、保护及管理方面的高度认可&#xf…

图解算法数据结构-LeetBook-栈和队列04_望远镜中最高的海拔_滑动窗口

科技馆内有一台虚拟观景望远镜&#xff0c;它可以用来观测特定纬度地区的地形情况。该纬度的海拔数据记于数组 heights &#xff0c;其中 heights[i] 表示对应位置的海拔高度。请找出并返回望远镜视野范围 limit 内&#xff0c;可以观测到的最高海拔值。 示例 1&#xff1a; 输…

Leetcode2938. 区分黑球与白球

Every day a Leetcode 题目来源&#xff1a;2938. 区分黑球与白球 解法1&#xff1a;贪心 把 ‘0’ 挪到相应的位置。 类似于冒泡排序的思想&#xff0c;把 ‘0’ 挪到相应的位置。 示例&#xff1a; 代码&#xff1a; /** lc appleetcode.cn id2938 langcpp** [2938] 区…

【无矶之谈】编码能力堪比Copilot、Cursor、GPT-国内可用的智能AI编程

前言简述 Copilot Copilot 是一款由 OpenAI 推出的人工智能代码自动补全AI工具 早在2022年4月&#xff0c;我便写了一篇Github Copilot的申请及在Pycharm的配置和使用&#xff0c;那个时候我便在用AI进行编程&#xff0c;当时虽然用的不是很多&#xff0c;但也算接触了AI。 …

C#的类型转换

目录 一、简介二、基本类型转换1.整数类型转换1.隐式转换2.显式转换 2.浮点类型转换1.隐式转换2.显式转换 3.字符类型转换1.字符到整数的转换2.整数到字符的转换 4.布尔类型转换1.布尔到整数的转换2.整数到布尔的转换 三、隐式转换和显式转换四、装箱和拆箱五、自定义类型转换六…

2023年11月18日骑行海囗林场公园赏枫叶之旅:一场秋天的色彩盛宴

随着人们生活水平的提高&#xff0c;越来越多的人开始追求生活的品质和乐趣。骑行作为一种健康、环保的出行方式&#xff0c;受到了广泛的喜爱。在秋天这个美丽的季节&#xff0c;骑行海囗林场森林公园赏枫叶更是一种别样的体验。校长将为您记录这场秋天的色彩盛宴&#xff0c;…

VueH5公众号分享到微信朋友圈或好友

场景需求&#xff1a; 一般分享场景是在当前页面分享当前页面&#xff0c;但是业务需求是&#xff0c;在当前页面分享好几个其他页面的链接到朋友圈和好友。 PS&#xff1a;微信自带的分享面板是无法第三方唤起的&#xff0c;只能点三个点。 其次在微信公众号页也不支持自定义…

影视行业如何远程完整快速传输大文件?

影视行业是一个充满创意和协作的领域。在影视制作中&#xff0c;涉及到多个环节和部门&#xff0c;包括编剧、导演、摄影、剪辑、配音、视效等。这些环节和部门通常分布在不同的地点&#xff0c;甚至不同的国家。因此&#xff0c;影视制作过程中需要频繁进行远程传输&#xff0…

如果文件已经存在与git本地库中,配置gitignore能否将其从git库中删除

想把项目的前后台代码放到同一个git仓库管理&#xff0c;由于未设置.gitignore&#xff0c;就使用vscode做stage操作&#xff08;相当于git add . 命令 其中【.】点表示全部文件&#xff09;&#xff0c;观察将要入库的文件发现&#xff0c;node_modules、target、.idea、log等…