算法——回溯与剪枝(Backtracking and pruning)
算法之回溯与剪枝(Backtracking and pruning)
- 思想:将回溯法与分支限界法原理结合、应用访问,用剪枝来排除不满足解的情况来提高算法的执行效率
- 算法总结:回溯法的优点是可以遍历所有的解的空间,容易编程,也可以在遍历的过程中除去不满足解空间的路径,大大的减少了深度遍历所带来的资源的巨大消耗。
回溯法的步骤: |
---|
1.找出能解决问题的所有的解 |
2.用递归的思想来一个解一个解的进行遍历和计算 |
3.在计算各个解的过程中根据要求,记录题目要求的解 |
4.对不满足解的路径进行剔除 |
5.最后回溯到起点 |
下面是一些例题,可以帮助大家理解和学习回溯键值的算法思想
- 走迷宫
在一个 m×n 的迷宫里,从起点开始,依次按东(右)、南(下)、西(左)、北(上) 4 个方向探索通路,直至达到终点为止。迷宫由字符组成,W表示墙,. 表示空地,请编写程序,输出你找到的首条通道。
思路:从起点时开始出发依次按照右下左上的顺序进行深度探索(用一个数组来存储依次遍历的顺序),如果在遍历的过程中出现坐标越界或者进入“死胡同”(其它的三个方向都是墙)那么就回退到上一个位置,再继续探索下一个位置,直到走到迷宫出口。
样例1:
5 7
W W . W W W W
W . . . W . .
W . W W W . W
W . W . . . W
W W W . W W W
0 2
4 3
输出:
None
样例2:
5 7
W W . W W W W
W . . . W . .
W . W W W . W
W . . . W . W
W W W . W W W
0 2
4 3
输出:
W W * W W W W
W * * o W . .
W * W W W . W
W * * * W . W
W W W * W W W
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define check(i,j,m,n) i<1||j<1||i>m||j>nconst int ma=1000;
char my_place[ma][ma];
int is_cross[ma][ma];
int m,n,x,y,x2,y2,t;
int my_move[4][2]={{0,1},{1,0},{0,-1},{-1,0}};void walk(int i,int j);
bool no_path(int i,int j);int main(){cin>>m>>n;for(int i=1;i<=m;i++)for(int j=1;j<=n;j++)cin>>my_place[i][j];cin>>x>>y>>x2>>y2;x+=1;y+=1;x2+=1;y2+=1;walk(x,y);if(t==0) cout <<"None"<<endl;else{for(int i=1;i<=m;i++){for(int j=1;j<=n;j++)if(j==1) cout<<my_place[i][j];else cout<<" "<<my_place[i][j];cout<<endl;}}return 0;
}bool no_path(int i,int j){if(is_cross[i-1][j]==1&&my_place[i][j+1]=='W'&&my_place[i+1][j]=='W'&&my_place[i][j-1]=='W')return true;else if(is_cross[i][j+1]==1&&my_place[i+1][j]=='W'&&my_place[i][j-1]=='W'&&my_place[i-1][j]=='W')return true;else if(is_cross[i+1][j]==1&&my_place[i][j+1]=='W'&&my_place[i-1][j]=='W'&&my_place[i][j-1]=='W')return true;else if(is_cross[i][j-1]==1&&my_place[i-1][j]=='W'&&my_place[i][j+1]=='W'&&my_place[i+1][j]=='W')return true;return false;
}
void walk(int i,int j){if(i==x2&&j==y2){is_cross[i][j]=1;my_place[i][j]='*';t=1;return;}if(no_path(i,j)) {my_place[i][j]='o';return;}for(int j1=0;j1<4;j1++){int newx=i+my_move[j1][0];int newy=j+my_move[j1][1];if(t==1||check(newx,newy,m,n)) return;if(my_place[newx][newy]!='W'&&is_cross[newx][newy]==0) {is_cross[i][j]=1;my_place[i][j]='*';walk(newx,newy);}}
}
- 0/1背包问题
0/1背包问题。给定一载重量为W的背包及n个重量为wi、价值为vi的物体,1≤i≤n,要求而且重量和恰好为W具有最大的价值。
思路:这道题本质是全排列的问题,即罗列出所有的可能的选择的组合,然后计算出每个组合的价值,最后求出最大的价值即可。
输入样例1:
5 10
2 6
2 3
6 5
5 4
4 6
输出样例1:
1 2 5
15
输入样例2:
2 10
11 2
13 100
输出样例2:
No
0
代码如下:
// Created by Chenglong Shi on 2021/11/3.
// Only can use to study
// Once found commercial or illegal use will be pursued to the end
// Banning plagiarism
// Email:2230307855@qq.com
// 内部可能含有拼音和汉语注释
// by 史成龙
// 方法:
//
#include<bits/stdc++.h>
using namespace std;const int ma=50;struct goods{int weight,space;goods(){weight=space=0;}
};goods things[ma];
int path[ma];
int dp[ma][ma];
int w,n,top,best;void put_goods();
void get_path();int main(){cin>>n>>w;for(int i=1;i<=n;i++) cin>>things[i].space>>things[i].weight;put_goods();best=dp[n][w];get_path();if(!best){cout<<"No"<<endl;cout<<"0";}else{for(int i=top-1;i>=0;i--)cout<<path[i]<<" ";cout<<"\n"<<best;}return 0;
}void put_goods(){for(int i=1;i<=n;i++){for(int j=1;j<=w;j++){if(things[i].space>j) dp[i][j]=dp[i-1][j];elsedp[i][j]=max(dp[i-1][j],dp[i-1][j-things[i].space]+things[i].weight);}}
}
void get_path(){int k=w;for(int i=n;i>=1;i--) {if (dp[i][k] == (dp[i - 1][k - things[i].space] + things[i].weight)) {path[top++] = i;k = w - things[i].space;}}
}
- 集合的划分
集合的划分
思路:这是一个贝尔数的应用例子,
1
1 2
2 3 5
5 5 8 13….
用数组进行存储a[n][n]就是要求的解
输入样例:
5
输出样例:
52
代码如下:
#include<bits/stdc++.h>
using namespace std;const int ma=5e3+1;int bell[ma][ma];
int n;void init();int main(){cin>>n;init();//打表cout<<bell[n][n]; return 0;
}void init(){bell[1][1]=1; bell[2][1]=1; bell[2][2]=2;bell[3][1]=2; bell[3][2]=3; bell[3][3]=5;for(int i=4;i<=n;i++){int begin=bell[i-1][i-1];int be=0,en=0;for(int j=1;j<=i;j++){if(j==1) {bell[i][j]=begin;be=begin;}else if(j==i){bell[i][j]=be+en;}else{bell[i][j]=bell[i][j-1]+bell[i-1][j-1];if(j==(i-1)){en=bell[i][j];} }}}
}
- 半数集
给定一个自然数n,由n 开始可以依次产生半数集set(n)中的数如下(注意半数集是多重集)。
1. n∈set(n);
2. 在n 的左边加上一个自然数,但该自然数不能超过最近添加的数的一半;
3. 按此规则进行处理,直到不能再添加自然数为止。
例如,set(6)={6,16,26,126,36,136}。半数集set(6)中有6 个元素。
思路:每一个数的半数集都与前面的数到此数的一半相对应,然后加上1就是当前数的半数集的个数
输入样例:
6
输出样例:
6
代码如下:
#include<bits/stdc++.h>
using namespace std;int n;
const int ma=61;
int key[ma];void init();//打表计算int main(){init();cin>>n;cout<<key[n];return 0;
}void init(){key[1]=1;for(int i=2;i<=ma;i++){for(int j=1;j<=i/2;j++)key[i]+=key[j];key[i]++;}
}
- 排列问题
(0<m≤26) 个大写字母中任意选出 n (0<n≤m) 个字母排成一行,一共有多少种排列?请编写程序,输入 m 和 n,输出从 A 开始的连续 m 个字母中任取 n 个字母的所有排列。
要求:每行输出一个排列,按字典序输出.
思路:先用char数组存储A到N的数据,然后用一个全局变量来表示当前读到第几个字母,如果读到N就回退再读其它的方案,直到所有的方案读取完毕。
输入样例:
3 2
输出样例:
AB
AC
BA
BC
CA
CB
代码如下:
// Created by Chenglong Shi on 2021/10/31.
// Only can use to study
// Once found commercial or illegal use will be pursued to the end
// Banning plagiarism
// Email:2230307855@qq.com
// 内部可能含有拼音和汉语注释
// by 史成龙
// 方法:回溯+全局变量控制
//
#include<stdio.h>const int ma=30;
int vis[ma],m,n,my_index=0;
char val[ma];
char re[ma];void show_permutation(int num);
void show_result();int main(){scanf("%d %d",&m,&n);for(int i=65;i<(65+m);i++) val[i-65]=(char)i;show_permutation(0);return 0;
}void show_result(){for(int i=0;i<n;i++) printf("%c",re[i]);printf("\n");
}
void show_permutation(int num){if(num>=n){show_result();return;}for(int i=0;i<m;i++){if(!vis[i]){re[my_index++]=val[i];vis[i]=1;show_permutation(num+1);vis[i]=0;my_index--;}}
}
- 希望以上知识可以对大家的学习有所帮助哈,这一部分挺难的,大家加油呀!
算法——回溯与剪枝(Backtracking and pruning)相关推荐
- 数据结构与算法(Python)– 回溯法(Backtracking algorithm)
数据结构与算法(Python)– 回溯法(Backtracking algorithm) 1.回溯法 回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条 ...
- 数字拆分问题算法回溯_回溯算法:求子集问题!
给「代码随想录」一个星标吧! ❝ 认识本质之后,这就是一道模板题 通知:我将公众号文章和学习相关的资料整理到了Github :https://github.com/youngyangyang04/le ...
- 【博弈论】极小极大搜索(Minimax Algorithm)与α-β剪枝(Alpha-Beta Pruning)
文章目录 一.极大极小搜索(Minimax Algorithm) 二.α-β剪枝(Alpha-Beta Pruning) 三.解题技巧 一.极大极小搜索(Minimax Algorithm) 在零和博 ...
- 【综述】闲话模型压缩之网络剪枝(Network Pruning)
关注上方"深度学习技术前沿",选择"星标公众号", 资源干货,第一时间送达! 来自 | CSDN 地址 | https://blog.csdn.net/jinz ...
- [Leetcode][第39题][JAVA][组合总和][回溯][dfs][剪枝]
[问题描述][中等] [解答思路] 1. 回溯 import java.util.ArrayDeque; import java.util.ArrayList; import java.util.De ...
- [Leetcode][第60题][JAVA][第k个排列][回溯][DFS][剪枝]
[问题描述][中等] [解答思路] 1. 回溯搜索算法 + 剪枝 ,直接来到叶子结点 时间复杂度:O(N^2) 空间复杂度:O(N) import java.util.Arrays;public cl ...
- 基本算法-回溯法(迷宫问题)
作者:翟天保Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 前言 本文介绍一种经典算法--回溯法,可作为迷宫问题的一种解法,以下是本篇文章正文内容,包括算法 ...
- 漫话算法[回溯]:从《大话西游》到掌握回溯思想!
快来和叮当学算法吧! From All CV to No CV!我的梦想是编程不再CV,算法不再死记硬背! 漫话算法[看电影学回溯算法]从<大话西游>到掌握回溯算法 回溯算法简介 回溯算法 ...
- Alpha-Beta剪枝(Alpha Beta Pruning)
Alpha-Beta剪枝算法(Alpha Beta Pruning) [说明] 本文基于<<CS 161 Recitation Notes - Minimax with Alpha Bet ...
最新文章
- 从LeNet到GoogLeNet:逐层详解,看卷积神经网络的进化
- python界面设计-手把手教你用Python设计一个简单的命令行界面
- 例解基于UML的面向对象分析与设计
- 人脸扫描建模_人脸识别智能锁安全吗?
- re.findall为什么返回的元素会是个元素为元组的列表类型呢
- HTTP1.1新增了五种请求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 、 CONNECT
- MIT免费生物信息课程 (代码、文档、数据) - 适合系统学习
- vs c语言程序调试方法,VS2015中的常用调试技巧分享
- 敏捷开发你必须知道的7件事
- oracle命令历史记录,oracle命令历史记录工具(rlwrap)
- 学习戴铭博文《从 ReactiveCocoa 中能学到什么?不用此库也能学以致用》的总结...
- 机器学习就那么回事儿
- 高斯克吕格投影分带计算
- 2022最新第四方聚合支付系统源码+详细搭建教程
- java layout各布局_java-Layout(布局管理器)
- 贝叶斯派的概率图模型概述(总)
- c#程序设计实训报告心得体会_C#实训总结报告
- 计算机网络:应用层 - 万维网 WWW、HTTP 协议以及 HTML 语言
- SDRAM DQM的解释
- 各大AI 开放平台一览
热门文章
- Office 2019 激活-探索(仅供参考)
- app表白 生日 小游戏 表白
- 【贪心-单调栈】中山纪念中学暑期游Day12——灵知的太阳信仰
- 金融風暴下,“杨白劳”与“黄世仁”的年关心态
- 2岁内婴幼儿过敏患病率达40.9%
- 查杀新rundl132.exe病毒的过程
- js实现复制文本及其排版格式
- 一篇文章吃透:为什么加载数据库驱动要用Class.forName()
- android手机能用ios吗,安卓手机真的可以刷苹果iOS系统吗?
- python读json文件数组_如何在python中从json文件读取json对象数组