深度优先搜索
深度优先搜索算法(Depth First Search,简称DFS):一种用于遍历或搜索树或图的算法。
沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过或者在搜寻时结点不满足条件,搜索将回溯到发现节点v的那条边的起始节点。整个进程反复进行直到所有节点都被访问为止。属于盲目搜索,最糟糕的情况算法时间复杂度为O(!n)。
1.部分和问题
给定整数a1,a2,…,an,判断是否可以从中选出若干数,使得他们的和恰好等于k
- 输入1:整数n
- 输入2:n个整数an
- 输入3:整数k
样例输入1:
4
1 2 4 7
13
样例输出1:
Yes
样例输入2:
4
1 2 4 7
15
样例输出2:
No
将a1作为根节点,左边子树为a1被选用的情况,右边子树为a1不被选用的情况,用sum来计算被选数据的和
part_sum.hpp
#ifndef PART_SUM
#define PART_SUM
#include <bits/stdc++.h>
using namespace std;
#define max_N 100000005
class PartSum
{
public:
bool dfs(int i,int sum);
void creat();
void solve();
private:
int n,k;
int a[max_N];
};
bool PartSum::dfs(int i,int sum){
if(i == n){
return (sum == k);
}
//左子树,a[i]被选用的情况
if(dfs(i + 1, sum + a[i])){
return true;
}
//右子树,a[i]未选用的情况
if(dfs(i + 1, sum)){
return true;
}
cout << "i = " << i << endl;
return false;
}
void PartSum::creat(){
cin >> n;
for (int i = 0; i < n; i++){
cin >> a[i];
}
cin >> k;
}
void PartSum::solve(){
if (this->dfs(0,0)){
cout << "Yes";
}else{
cout << "No";
}
}
#endif
2.八领域积水问题
有一个大小为 M × N 的园子 雨后积起了水 八连通的积水被认为是连接在一起的 请求出园子里共有多少个水洼
- 第一行输入一个整数N
- 第二行输入一个整数M
- 接下来的 M 行 N 列表示园子的范围,其中“w”为积水
样例输入:
w . . . . . . . . w w .
. w w w . . . . . w w w
. . . . w w . . . w w .
. . . . . . . . . w w .
. . . . . . . . . w . .
. . w . . . . . . w . .
. w . w . . . . . w w .
w . w . w . . . . . w .
. w . w . . . . . . w .
. . w . . . . . . . w .
样例输出:
3
lake_couting.hpp
#ifndef LAKE_COUNTING
#define LAKE_COUNTING
#include <bits/stdc++.h>
using namespace std;
#define max_N 105
class LakeCounting
{
public:
char field[max_N][max_N];
int M,N;
public:
void dfs(int x,int y);
void solve();
void creatfield();
};
void LakeCounting::dfs(int x,int y){
field[x][y] = '.';
for(int dx = -1; dx <= 1; dx++){
for(int dy = -1; dy <= 1; dy++){
int nx = x + dx , ny = y + dy;
if(nx >= 0 && nx < M && ny >= 0 && ny < N && field[nx][ny] == 'w'){
dfs(nx,ny);
}
}
}
}
void LakeCounting::solve(){
int res = 0;
cout << "M = " << M << " N = " << N << endl;
for(int i = 0; i < M; i++){
for(int j = 0; j < N; j++){
if(field[i][j] == 'w'){
dfs(i,j);
res++;
}
}
}
cout << "lake = " << res << endl;
}
void LakeCounting::creatfield(){
cout << "请输入园子的长度:";
cin >> M ;
cout << "请输入园子的宽度:";
cin >> N ;
for(int i = 0; i < M; i++){
for(int j = 0; j < N; j++){
cout << "请输入数据: field[" << i << "][" << j << "] = ";
cin >> field[i][j];
}
}
}
#endif
3.旅行商问题(无向图最短路径遍历)
输入一个无向图,求从起点到终点的所有路径
转换为矩阵表达
样例输入:
citynum
roadnum
a b c
a b c
a b c
. . .
- citynum 表示城市数量
- roadnum 表示路径数量
- a b c 表示城市 a 和城市 b 可以互相到达,路程为 c 公里
undirected_graph.hpp
#ifndef UNDIRECTED_GRAPH
#define UNDIRECTED_GRAPH
#include <fstream>
#include <iostream>
#include <time.h>
#include <vector>
#include <limits.h>
#define max_N 105
#define inf INT_MAX
using namespace std;
class UndirectedGraph{
public:
int input[max_N][3];
int graph[max_N][max_N];
int roadnum;
int min_dist = inf;
int citynum;
int cur_dis = 0;
bool book[max_N];
vector<int> path;
public:
void creat();
void initial_graph();
void dfs(int start_id,int end_id,int &min_dis,int cur_dis,int cur_id);
void findpath();
};
void UndirectedGraph::creat(){
ifstream file("./undirected.txt");
if (!file.is_open())
{
cout << "打开文件失败,请检查文件路径是否正确" << endl;
}
file >> citynum;
file >> roadnum;
cout << "citynum = " << citynum << endl;
cout << "roadnum = " << roadnum << endl;
for (int i = 0; i < roadnum; i++){
for (int j = 0; j < 3; j++){
file >> input[i][j];
// cout << "input[" << i << "][" << j << "] = " << input[i][j] << endl;
}
}
file.close();
}
void UndirectedGraph::initial_graph(){
for (int i = 0; i < max_N; i++){
for (int j = 0; j < max_N; j++){
if(i == j){
graph[i][j] = 0;
}else{
graph[i][j] = inf;
}
}
book[i] = false;
}
for(int i = 0; i < roadnum; i++){
graph[input[i][0]][input[i][1]] = input[i][2];
graph[input[i][1]][input[i][0]] = input[i][2];
}
// print graph
for(int i = 1; i <= citynum; i++){ // graph下标从1开始
for(int j = 1; j <= citynum; j++){
if(graph[i][j] == inf){
cout << setw(4) << "inf" << " ";
}else{
cout << setw(4) << graph[i][j] << " ";
}
}
cout << endl;
}
}
void UndirectedGraph::findpath(){
dfs(1,5,min_dist,cur_dis,1);
cout << "min_dist = " << min_dist << endl;
cout << "THE BEST PATH:" << endl;
for(int i = 0; i < path.size(); i++){
cout << path[i] ;
if(path[i] != path.back()){
cout << " --> ";
}
}
cout << endl;
}
void UndirectedGraph::dfs(int start_id,int end_id,int &min_dis,int cur_dis,int cur_id){
book[cur_id] = true;
if(cur_dis > min_dis){
return;
}
if(cur_id == end_id){
if(cur_dis < min_dis){
min_dis = cur_dis;
path.clear();
for(int k = 1; k <= citynum; k++){
if(book[k]) path.push_back(k) ;
}
}
return;
}
for(int k = 1; k <= citynum; k++){
if(!book[k] && graph[cur_id][k] != inf){
dfs(start_id, end_id, min_dis, cur_dis + graph[cur_id][k], k);
book[k] = false;
}
}
return;
}
#endif
4.主程序与测试用例
dfs_demo.cpp
/* ***********
* DFS Algorithm DEMO
* @Prame
*********** */
#include "dfs_demo/part_sum.hpp"
#include "dfs_demo/lake_couting.hpp"
#include "dfs_demo/undirected_graph.hpp"
int main () {
//* problem 1
// PartSum partsum;
// partsum.solve();
//* problem 2
// LakeCounting lakecounting;
// lakecounting.creatfield();
// lakecounting.solve();
//* problem 3
// UndirectedGraph undirectedgraph;
// undirectedgraph.creat();
// undirectedgraph.initial_graph();
// undirectedgraph.findpath();
return 0;
}
problem3 测试用例
----
undirected.txt
5
7
1 2 2
1 3 4
1 5 10
2 3 3
3 4 4
3 5 3
4 5 5