bool visit[];
void dfs(){
if(返回条件 == true){
return;
}
if(!visit[i]){
visit[i] = true;
//operation1
dfs();
//operation2
visit[i] = false;
}
return;
}
void dfs(int x,int y,int z)//坐标,层次/步数
{
if (z.../坐标达到条件)//终止条件
{
执行
return;
}
for (int i = 0; i < 可扩展的路径数; i++)//遍历
{
if (符合条件)
{
flag=1;
dfs(下一种情况);
flag=0;//回溯
}
}
}
用path 数组保存排列,当排列的长度为 n 时,是一种方案,输出。
用st 数组表示数字是否用过。当st[i]为true 时,i 已经被用过了,st[i] 为 false 时,i 没被用过。
dfs(i) 表示的含义是:在path[i] 处填写数字,然后递归的在下一个位置填写数字。
回溯:第 i 个位置填写某个数字的所有情况都遍历后, 第 i 个位置填写下一个数字。
#include<iostream>
using namespace std;
const int N = 10;
int path[N];
bool st[N];//标注数字是否被用过
int n;
void dfs(int x)
{
if(x == n)//数字填完了,输出,走到第n个位置
{
for(int i = 0; i < n; i ++) printf("%d ", path[i]);
puts("");
return;
}
for(int i = 1; i <= n; i ++)//这里是空位上可以选择的数字为:1 ~ n
if(!st[i])//如果数字 i 没有被用过
{
path[x] = i;//放入空位
st[i] = true;//放入空位,则数字被用,修改状态
dfs(x + 1);//填下一个位
st[i] = false;//回溯,恢复现场,数字i后续可用
}
}
int main()
{
cin >> n;
dfs(0);// 在path[0]处开始填数
return 0;
}
迷宫问题——迷宫从起点到终点有没有路径,有几条,求最短路径
(深搜暴搜)https://www.bilibili.com/video/BV1uR4y1s7FA?vd_source=cecc6ff6e883f42b10c1d53026d0846e
题目描述
w设有一个N*N(2<=N<10)方格的迷宫,入口和出口分别在左上角和右上角。迷宫格子中分别放0和1,0表示可通,1表示不能,入口和出口处肯定是0。迷宫走的规则如下所示:即从某点开始,有八个方向可走,前进方格中数字为0时表示可通过,为1时表示不可通过,要另找路径。找出所有从入口(左上角)到出口(右上角)的路径(不能重复),输出路径总数,如果无法到达,则输出0。
输入
第一行输入一个整数n
然后是n行,每行n个数,分别为0 或1
输出
输出一个整数表示路径数
样例输入
3
0 0 0
0 1 1
1 0 0
样例输出
2
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
bool a[20][20];
int n,ans=0;
int dx[9]={0,-1,-1,-1,0,0,1,1,1};
int dy[9]={0,-1,0,1,-1,1,-1,0,1};
void dfs(int cx,int cy)//从cx cy出发
{
if (cx==1&&cy==n)//从cx xy出发,发现就是目标结点,
{
ans++;
return ;// 返回调用该函数的上一层
}
for(int i=1;i<=8;i++)
{
//cx cy方向数组变换
int tx=cx+dx[i];
int ty=cy+dy[i];
if(tx>=1&&tx<=n&&ty>=1&&ty<=n&&a[tx][ty]==0)//遍历,不能越界 ,并且能通行
{
a[tx][ty]=1;//标记
dfs(tx,ty);//搜索
a[tx][ty]=0;//取消标记
}
}
return;
}
int main()
{
cin>>n; //初始化地图
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cin>>a[i][j];
}
}
a[1][1]=1;//访问数组,0表示未访问,1表示访问,默认为0,表示从11点出发,不能再回到11点
dfs(1,1);//开始搜索
cout<<ans<<endl;//所有路径搜完,打印
return 0;
}
连通块——踏青
蒜头君和他的朋友周末相约去召唤师峡谷踏青。他们发现召唤师峡谷的地图是由一块一块格子组成的,有的格子上是草丛,有的是空地。草丛通过上下左右 4个方向扩展其他草丛形成一片草地,任何一片草地中的格子都是草丛,并且所有格子之间都能通过上下左右连通。如果用’#‘代表草丛,’.'代表空地,下面的峡谷中有 2 片草地。
##..
..##
处在同一个草地的 2 个人可以相互看到,空地看不到草地里面的人。他们发现有一个朋友不见了,现在需要分头去找,每个人负责一片草地,蒜头君想知道他们至少需要多少人。
输入格式
第一行输入 n, m (1≤n,m≤100)表示峡谷大小。
接下来输入 n行字符串表示峡谷的地形。
输出格式
输出至少需要多少人。
样例输入
5 6
.#....
..#...
..#..#
...##.
.#....
样例输出
5
想法:求人->求草地片数,两个草丛->草地
输入地图,对于每个未标记的草丛#,四个方向递归,搜索完毕之后得到一片草地,这片草地只需要一个人,不需要把标记还原,(然后再从未被标记过的草丛处开始搜索,遇到未标记的草丛则标记,遇到空地则返回),然后从该草丛处开始搜索来确定有多少草丛与该草丛直接或间接相连,即重复上述步骤,直到所有的草丛都被搜过。
#include <iostream>
using namespace std;
int n, m, ans = 0;
char map[105][105];
bool vis[105][105];
int dx[5] = {0, 1, 0, -1, 1};
int dy[5] = {0, 1, 0, -1, 0};
void dfs(int x, int y) { //从x y出发
if (x < 0 || x >= n || y < 0 || y >= m || vis[x][y] == 1 || map[x][y] == '.') {
return;
}
vis[x][y] = 1;
for (int i = 1; i <= 4; i++) {
//x y方向数组变换
int tx = x + dx[i];
int ty = y + dy[i];
if (tx >= 0 && tx < n && ty >= 0 && ty < m && vis[tx][ty] == 0) { //遍历,不能越界 ,并且能通行
vis[tx][ty] = 1; //标记
dfs(tx, ty); //搜索
}
}
}
int main() {
cin >> n >> m; //初始化地图
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> map[i][j];
}
}
//开始搜素
for (int i = 0; i < n; i++) {
for (int j= 0; j < m; j++) {
if (map[i][j] == '#' && vis[i][j] == 0) { //条件:草丛,并且没访问过
// vis[i][j] = 1; //标记
dfs(i, j); //开始搜索
ans++;//草丛数量++
}
}
}
cout << ans << endl;
return 0;
}
迷宫解的方案数
题目描述:
问,在不走重复路径的情况下,总共有多少不同可以到达终点的路径呢?蒜头君稍加思索便给出了答案,你要不要也来挑战一下?
输入格式:
第一行输入两个整数 n(1≤n≤11), m(1≤m≤11),表示迷宫的行和列。
然后有一个n×m 的地图,地图由’.’、’#’、‘s’、‘e’这四个部分组成。’.‘表示可以通行的路,’#'表示迷宫的墙,'s’表示起始点,'e’表示终点。
输出格式
输出一个整数,表示从’s’到达’e’的所有方案数。
样例输入
5 5
s####
.####
.####
.####
....e
样例输出
1
思路:找到所有解,所以要取消标志
#include<iostream>
using namespace std;
int n,m,ans;
char map[20][20];
bool vis[20][20];
int dx[5]={0,1,0,-1,0};
int dy[5]={0,0,-1,0,1};
void dfs(int x,int y) {
if(x < 0 || x >= n || y < 0 || y >= m || vis[x][y] == 1 || map[x][y] == '#'){
return;// 返回调用该函数的上一层
}
if(map[x][y]=='e'){
ans++;
return;
}
vis[x][y]==1;
for(int i=1;i<=4;i++)//方向数组变换
{
int cx=x+dx[i];
int cy=y+dy[i];
if( map[x][y] == 'e'){
vis[cx][cy]=1;//标记
dfs(cx,cy);
vis[cx][cy]=0;
ans++;
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>map[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(map[i][j]=='s'){ //条件:从起点开始搜索
ans++;
dfs(i,j);
}
}
}
cout << ans << endl;
return 0;
}
打印路径——马走日
#include<bits/stdc++.h>
using namespace std;
int x[10],y[10],s; //每找到一个点,就记录,且节点数不会超过列数9
bool vis[5][9];
int dx[5]={0,2,1,-1,-2};
int dy[9]={0,1,2,2,1};
void dfs(int cx, int cy,int cur)//cur表示(cx,cy)是第几个节点
{
x[cur]=cx;y[cur]=cy;//记录
if(cx==4&&cy==8)
{
s++;
cout<<s<<":0,0";
for(int i=2;i<=cur;i++){
cout<<"->"<<x[i]<<","<<y[i];
}
cout<<endl;
return;
}
for(int i=0;i<=4;i++)
{
int tx=cx+dx[i];
int ty=cy+dy[i];
if(tx>=0&&tx<=4&&ty>=0&&ty<=8&&vis[tx][ty]==0)
{
vis[tx][ty]=1;
dfs(tx,ty,cur+1);
vis[tx][ty]=0;
}
}
}
int main()
{
vis[0][0]=1;
dfs(0,0,1);//从00点出发(0,0)作为第一个节点去搜下一个节点
}