1.1 DFS模板(深度优先遍历)
- 模板
全局状态变量
void dfs(当前状态)
{if(当前状态是目标状态) // 判断进行相应处理(输出当前解、更新最优解、退出返回等)// 扩展for(所有可行的新状态){if(新状态没有访问过 && 需要访问) // 可行性剪枝、最优性剪枝、重复性剪枝{标记dfs(新状态);取消标记}}
}
int main()
{...dfs(初始状态);...
}
-
例题:
题目描述
输出自然数 1∼n 所有不重复的排列,即 n 的全排列,要求所产生的任一数字序列中不允许出现重复数字。
输入格式
一行,一个整数 n。
输出格式
输出由 1∼n 组成的所有不重复的数字序列。每行一个序列,行内数字之间用空格隔开。
样例
输入:
3
输出:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1数据范围
对于 100% 的测试数据满足:1≤n≤9。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,a[10];
bool f[10];void prin(){for(int i=1;i<=n;i++){cout<<a[i]<<" ";}cout<<endl;
} void dfs(int k){for(int i=1;i<=n;i++){if(f[i]==false){a[k]=i;f[i]=true;if(k==n) prin();else dfs(k+1);f[i]=false;}}}int main(){cin>>n;dfs(1);return 0;
}
1.2 BFS模板(广度优先遍历)
-
模板
全局状态变量 void BFS() {定义状态队列初始状态入队while(队列不为空){取出队首状态作为当前状态if(当前状态是目标状态)进行相应处理(输出当前解、更新最优解、退出返回等)elsefor(所有可行的新状态){if(新状态没有访问过 && 需要访问){新状态入队}}} }
-
例题:
题目描述
有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第 i层楼(1≤i≤N*)上有一个数字 Ki(0≤Ki≤N)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如:从一楼开始,3 3 1 2 5代表了Ki(K1=3,K2=3,……) 。在一楼,按“上”可以上 3 层到 4 楼,按“下”是不起作用的,因为没有 -2 楼。那么,从 A 楼到 B 楼至少要按几次按钮呢?
输入格式
输入共有二行,第一行为三个用空格隔开的正整数,表示N*,A,B,第二行为 N 个用空格隔开的正整数,表示Ki*。
输出格式
输出仅一行,即最少按键次数,若无法到达,则输出 -1。
样例输入与输出
输入数据
5 1 5 3 3 1 2 5
输出数据
3
样例解释
输入解释
第一行的数据 5表示总共5层楼,第二个数据1表示初始在1楼,第三个数据5表示我们最终的目的地是5楼。
第二行的数据 第二行输入了5个数,分别表示每一层的电梯能上下几层。
第一个数3 表示在1楼可以上3层楼,到达4楼;也可以下3层楼,但是我们没有-2层楼,所以从1楼下3层不行。
第二个数3 表示在2楼可以上3层楼,到达5楼;也可以下3层楼,但是我们没有-1层楼,所以从2楼下3层不行。
第三个数1 表示在3楼可以上1层楼,到达4楼;也可以下1层楼,到达2楼。输出解释
那么我们初始在1楼,只能上3层到达4楼,在4楼只能下2层到达2楼,然后上3层到达5楼。总共用了3步,所以最终输出3。
数据范围
对于 100% 的测试数据满足:1≤N≤200,1≤A,B≤N。
-
代码:
#include <bits/stdc++.h> using namespace std;int n, a, b; // 输入的数值范围n,起点a,终点b int x[205], step[205]; // 数组x用于存储每个位置可以跳跃的步数,step数组用于标记每个位置的步数 queue<int> q; // 队列用于广度优先搜索// 广度优先搜索函数 void bfs() {q.push(a); // 将起点a加入队列step[a] = 0; // 将起点的步数标记为0while (!q.empty()) { // 当队列不为空时循环int t = q.front(); // 取出队首元素q.pop(); // 弹出队首元素if (t == b) { // 如果当前位置等于终点bcout << step[b]; // 输出步数return ; // 结束搜索}if (t - x[t] >= 1 && !step[t - x[t]]) { // 如果向下跳不越界且下一个位置未被访问过q.push(t - x[t]); // 将下一个位置加入队列step[t - x[t]] = step[t] + 1; // 更新下一个位置的步数}if (t + x[t] <= n && !step[t + x[t]]) { // 如果向上跳不越界且下一个位置未被访问过q.push(t + x[t]); // 将下一个位置加入队列step[t + x[t]] = step[t] + 1; // 更新下一个位置的步数}}cout << -1; // 如果无法到达终点b,输出-1 } int main() {cin >> n >> a >> b; // 输入数值范围n,起点a,终点bfor (int i = 1; i <= n; i++) // 输入每个位置的可跳跃步数cin >> x[i];bfs(); // 进行广度优先搜索 }