深度优先搜索- -简单版

在图上寻找路径

int main() {
    //将所有点都标记为新点;
    //起点 = 1;
    //终点 = 8;
    cout << Dfs(起点);
    return 0;
}

判断从V出发能否找到终点

bool Dfs(V) {//从V出发判断是否能到终点
	if (V是终点)
		return true;
	if (V是旧点)
		return false;
	将V标记为旧点
	对和V相邻的每个节点U{
		if (Dfs(U) == true)
			return true;
		}
	 return false;
}

判断从V出发能否走到终点,如果能,要记录路径

Node path[MAX_LEN];//MAX_LEN取节点总数即可
int depth;
bool Dfs(V) {//从V出发进行遍历
	if (V是终点) {
		path[depth] = V;
		return true;
	}
	if (V是旧点) {
		return false;
	}
	将V标记为旧点;
	path[depth] = V;
	depth++;
	对和V相邻的每个节点U{
		if (Dfs(U) == true)
		return true;
	}
	--depth;
	return false;
}
int main() {
	将所有点标记为新点;
	depth = 0;
	if (Dfs(起点)) {
		for (int i = 0; i <= depth; i++)
			cout << path[i] << endl;
	}
    return 0;
}

遍历图上所有节点

Dfs(V) {//从V出发进行遍历
	if (V是旧点) {
		return;
	}
	将V标记为旧点;
	对和V相邻的每个点U{
		Dfs(U);
	}
}
int main() {
	将所有点都标记为新点;
	while (在图中能找到新点k) {
		Dfs(k);
	}
}

邻接矩阵

G[i][j]可以是自定义类型,可以是int,也可以是struct 

 邻接表

 城堡问题

1817:城堡问题​​​​​​

总时间限制: 

1000ms

内存限制: 

65536kB

描述

     1   2   3   4   5   6   7  
   #############################
 1 #   |   #   |   #   |   |   #
   #####---#####---#---#####---#
 2 #   #   |   #   #   #   #   #
   #---#####---#####---#####---#
 3 #   |   |   #   #   #   #   #
   #---#########---#####---#---#
 4 #   #   |   |   |   |   #   #
   #############################
           (图 1)

   #  = Wall   
   |  = No wall
   -  = No wall


图1是一个城堡的地形图。请你编写一个程序,计算城堡一共有多少房间,最大的房间有多大。城堡被分割成m*n(m≤50,n≤50)个方块,每个方块可以有0~4面墙。

输入

程序从标准输入设备读入数据。第一行是两个整数,分别是南北向、东西向的方块数。在接下来的输入行里,每个方块用一个数字(0≤p≤50)描述。用一个数字表示方块周围的墙,1表示西墙,2表示北墙,4表示东墙,8表示南墙。每个方块用代表其周围墙的数字之和表示。城堡的内墙被计算两次,方块(1,1)的南墙同时也是方块(2,1)的北墙。输入的数据保证城堡至少有两个房间。

输出

城堡的房间数、城堡中最大房间所包括的方块数。结果显示在标准输出设备上。

样例输入

4 
7 
11 6 11 6 3 10 6 
7 9 6 13 5 15 5 
1 10 12 7 13 7 5 
13 11 10 8 10 12 13 

样例输出

5
9

 思路:西墙1 :1;北墙2:10;东墙4:100;南墙8:1000.

每个方块有几面墙,二进制数位运算。

方块看作节点,相邻方块之间没有墙,则视为有边相连。房间数:所有极大连通子图数目;最大房间:所有极大连通子图中节点最多的那个

 对每一个房间,进行深搜,可以得到该节点所在的极大连通子图。房间数目- -染色,用的颜色种类

#include <iostream>
using namespace std;
int R, C;//行列数
int rooms[60][60];//存储图的信息
int color[60][60];//方块是否染过色的标记 标记
int maxRoomArea = 0, roomNum = 0;//最大的面积,房间数目
int roomArea;//正在探索的连通子图面积
void Dfs(int i, int k) {
	//从节点(i,k)出发,进行深度优先搜索
	//即搜素该节点所在的极大连通子图
	if (color[i][k])//递归结束
		return;
	roomArea++;//该方块加入房间,面积加1
	color[i][k] = roomNum;
	//对和(i,j)节点相邻的节点进行深搜
	//西墙1 :1;北墙2:10;东墙4:100;南墙8:1000
	if ((rooms[i][k] & 1) == 0&&k-1>=1)//向西走且不出界
		Dfs(i, k - 1);
	if ((rooms[i][k] & 2) == 0&&i-1>=1)//向北走且不出界
		Dfs(i - 1, k);
	if ((rooms[i][k] & 4) == 0&&k+1<=C)//向东走且不出界
		Dfs(i, k + 1);
	if ((rooms[i][k] & 8) == 0&&i+1<=R)//向南走且不出界
		Dfs(i + 1, k);
}
int main() {
	cin >> R >> C;
	for (int i = 1; i <= R; i++)
		for (int k = 1; k <= C; k++)
			cin >> rooms[i][k];
	memset(color, 0, sizeof(color));//所有点都标记为新点
	for (int i = 1; i <= R; i++)
		for (int k = 1; k <= C; k++) {//循环遍历所有的点
			if (!color[i][k]) {//没有染色标记- - 在图中能找到新点
				roomNum++;//找到了新的极大连通子图-新房间
				roomArea = 0;
				Dfs(i, k);//深搜
				maxRoomArea =
					max(roomArea, maxRoomArea);
			}
		}
	cout << roomNum << endl;
	cout << maxRoomArea << endl;
	//复杂度 O(R*C)
}

 踩方格

有一个方格矩阵,矩阵边界在无穷远处。我们做如下假设:

a. 每走一步时,只能从当前方格移动一格,走到某个相邻的方格上;
b. 走过的格子立即塌陷无法再走第二次;
c. 只能向北、东、西三个方向走;

请问:如果允许在方格矩阵上走 n 步,共有多少种不同的方案。

2 种走法只要有一步不一样,即被认为是不同的方案。

输入格式

允许在方格上行走的步数 n(n≤20)。

输出格式

计算出的方案数量。

输出时每行末尾的多余空格,不影响答案正确性

样例输入

2

样例输出

7

思路:

递归-- - 分类讨论

从(i,j)出发,走n步的方案数,等于以下三项的和:

1)下一步向北走,走到(i-1,j),然后从(i-1,j)走n-1步的方案数;前提(i-1,j)还没有走过

2)下一步向东走,走到(i,j+1),然后从(i,j+1)走n-1步的方案数;前提(i,j+1)还没有走过

3)下一步向西走,走到(i,j-1),然后从(i,j-1)走n-1步的方案数 。前提(i,j-1)还没有走过

再分析- - 深度优先搜索

从(i,j)出发,走n步的方案数(从(i,j)出发遍历),等于以下三项的和:

1)下一步向北走,走到(i-1,j),然后从(i-1,j)走n-1步的方案数;前提(i-1,j)还没有走过- - 相邻的新点

2)下一步向东走,走到(i,j+1),然后从(i,j+1)走n-1步的方案数;前提(i,j+1)还没有走过- - 相邻的新点

3)下一步向西走,走到(i,j-1),然后从(i,j-1)走n-1步的方案数 。前提(i,j-1)还没有走过- - 相邻的新点

递归边界: n等于0时,从(i,j)出发,走0步的方案数只有一种,就是走0步

#include <iostream>
using namespace std;
int visited[100][100];
int ways(int i, int j, int n) {
	//从点(i,j)出发,走n步的方案数- - 从某节点出发,遍历
	if (n == 0)
		return 1;
	visited[i][j] = 1;//标记为旧点
	int num = 0;
	if (!visited[i][j - 1])//向西走
		num += ways(i, j - 1, n - 1);
	if (!visited[i][j + 1])//向东走
		num += ways(i, j + 1, n - 1); 
	if (!visited[i - 1][j])//向北走
		num += ways(i - 1, j, n - 1);
	//以上求出了在先从(i,j)走的情况下,所有的情况
	//既然已经求出了这个num了,我们就应该撤去对(i,j)的标记
	//先走(m,n)的情况下,还可以再走(i,j),
	//前提是,在走(m,n)之前,没有走过(i,j)
	visited[i][j] = 0;//
	return num;
}
int main() {
	int n;
	cin >> n;
	//全部置为新点
	memset(visited, 0, sizeof(visited));

	//平面无限大,可以任选起点,
	//从(25,25)出发,走不超过20步不越界- - 省去判断
	cout << ways(25, 25, n) << endl;
	return 0;
}

一个状态,相当于图上的一个节点,(i,j,n)节点,与状态(i,j,n)相邻的状态是(i-1,j,n-1)、(i,j-1,n-1)、(i,j+1,n-1),相邻表示有边。

在一个图上,从节点(x,y,n)出发,其中x,y任选,n是20,走到一些目标节点(x1,y1,0),求一共有多少种走法。深搜,从图上的节点出发(某个状态),走到某个目标节点或者某些目标节点(某个或者某些状态),求解一共有多少种走法,或者最近路径,或者权值最小,等等。

水洼数

题目

分析:和城堡问题相同,方向数组 

 

#include <iostream>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <map>
using namespace std;
int n, m;
char field[105][105];
int visited[105][105];
int nextt[10][3] = {
	{-1,-1},{-1,0},{-1,1},
	{0,-1},{0,1},
	{1,-1},{1,0},{1,1}
};//方向数组
void Dfs(int x, int y) {
	if (visited[x][y])return;
	if (!visited[x][y]) {
		visited[x][y] = 1;
		if (field[x][y] == '.')return;
		for (int i = 0; i <= 7; i++) {
			int dx = nextt[i][0], dy = nextt[i][1];
			int nx = x + dx, ny = y + dy;
			if (nx >= 0 && nx < n && ny >= 0 && ny < m)
				Dfs(nx, ny);
		}
			
	}
	return;
}
void solve() {
	int res = 0;
	for(int i = 0;i <n;i++)
		for(int j = 0;j<m;j++)
			if (!visited[i][j] && field[i][j] == 'w') {
				Dfs(i, j);
				res++;
			}
	cout << res << endl;
}
void init() {
	cin >> n >> m;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			cin >> field[i][j];
	memset(visited, 0, sizeof(visited));
}
int main() {
	init();
	solve();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值