DFS相关的一些模板

/*请从main开始看*/

/*
SampleInput:

6 8 7
0 5
2 4
2 3
1 2
0 1
3 4
3 5
0 2
1 4
0 0
1 1
2 2
3 3
4 4
5 5
4 2 2
0 1
2 3
2 1
0 0

*/

#include<cstdio>
#include<cstring>
#include<list>
#include<stack>
#include<set>
using namespace std;
const int maxn = 100002;

list<int> point[maxn];///当然,你也可以使用vector实现
set<int> cc[maxn];///cc指连通分量
bool vis[maxn], color[maxn];
int edgeTo[maxn];///dfs出的路径
stack<int> path;
int beg, end, count;
bool isend, hascycle, isTwoColorable;

///复杂度:O(V+E)
///找路,从v到end
void dfs(int v)
{
	vis[v] = true;
	list<int>::iterator it;
	for (it = point[v].begin(); it != point[v].end(); ++it)
	{
		if (isend)
			return;
		int w = (int) * it;
		if (!vis[w])
		{
			edgeTo[w] = v;
			if (w == end)
			{
				isend = true;
				return;
			}
			dfs(w);
		}
	}
}

///找环,从beg到beg
void dfs(int v, int u)
{
	vis[v] = true;
	list<int>::iterator it;
	for (it = point[v].begin(); it != point[v].end(); ++it)
	{
		if (hascycle)
			return;
		int w = (int) * it;
		if (!vis[w])
		{
			edgeTo[w] = v;
			dfs(w, v);
		}
		else if (w != u && w == beg)
			///该已找到的点不是前一个点(上一层dfs的点)
			///说明从该点出发可以沿着另一条路回来,所以G有环。
		{
			edgeTo[w] = v;
			hascycle = true;
			return;
		}
	}
}

///简单找环
void simpledfs(int v, int u)
{
	vis[v] = true;
	list<int>::iterator it;
	for (it = point[v].begin(); it != point[v].end(); ++it)
	{
		if (hascycle)
			return;
		int w = (int) * it;
		if (!vis[w])
			dfs(w, v);
		else if (w != u)
			///该已找到的点不是前一个点(上一层dfs的点)
			///说明从该点出发可以沿着另一条路回来,所以G有环。
		{
			hascycle = true;
			return;
		}
	}
}

///双色否
void colordfs(int v)
{
	vis[v] = true;
	list<int>::iterator it;
	for (it = point[v].begin(); it != point[v].end(); ++it)
	{
		if (!isTwoColorable)
			return;
		int w = (int) * it;
		if (!vis[w])
		{
			color[w] = !color[v];
			colordfs(w);
		}
		else if (color[w] == color[v])
		{
			isTwoColorable = false;
			return;
		}
	}
}

///找连通分量,遍历型
void exdfs(int v)
{
	vis[v] = true;
	cc[count].insert(v);
	list<int>::iterator it;
	for (it = point[v].begin(); it != point[v].end(); ++it)
	{
		int w = (int) * it;
		if (!vis[w])
			exdfs(w);
	}
}

///应用1
///输出起点v到终点w的路径,以空格隔开
///如果不存在,则输出-1
inline void printpath(int v, int w)
{
	memset(vis, 0, sizeof(vis));
	memset(edgeTo, -1, sizeof(edgeTo));
	isend = false;
	while (!path.empty())
		path.pop();
	if (v != w)
	{
		end = w;
		dfs(v);
		for (int x = w; x != v; x = edgeTo[x])///先从w到v
		{
			if (~edgeTo[x]) /// edgeTo[x] != -1
				path.push(x);
			else ///说明v,w在两个不同的连通分量上
			{
				printf("-1\n");
				return;
			}
		}
		printf("%d", v);
		while (!path.empty())
		{
			printf(" %d", path.top());
			path.pop();
		}
		printf("\n");
	}
	else///找一个环
	{
		hascycle = false;
		beg = v;
		dfs(v, v);
		if (hascycle)
		{
			for (int x = edgeTo[v] ; x != v; x = edgeTo[x])
				path.push(x);
			printf("%d", v);
			while (!path.empty())
			{
				printf(" %d", path.top());
				path.pop();
			}
			printf(" %d\n", v);
		}
		else
			printf("-1\n");
	}
}

///应用2
///判断是否为无环图(假设不存在自环或平行边)
inline void hasCycle(int n)
{
	memset(vis, 0, sizeof(vis));
	hascycle = false;
	for (int i = 0; i < n; ++i)
		if (!vis[i])
			simpledfs(i, i);
}

///应用3
///返回连通子图的个数
inline int count_connected_subgraph(int n)
{
	memset(vis, 0, sizeof(vis));
	for (int i = 1; i <= count; ++i)
		cc[i].clear();
	count = 1;
	for (int i = 0; i < n; ++i)
	{
		if (!vis[i])
		{
			exdfs(i);
			++count;
		}
	}
	return count - 1;
}

///应用4
///判断G是否为二分图
inline void checkTwoColor(int n)
{
    memset(vis, 0, sizeof(vis));
	memset(color, 0, sizeof(color));
	isTwoColorable = true;
	for (int i = 0; i < n; ++i)
		if (!vis[i])
			colordfs(i);
}

int main(void)
{
	int n, m, k, temp, v, w;///点数=n,边数=m,查询数=k
	while (~scanf("%d%d%d", &n, &m, &k))
	{
		///0. 初始化
		temp = m;
		while (temp--)
		{
			scanf("%d%d", &v, &w);///这里输入要求为0~(n-1)
			point[v].push_front(w);
			point[w].push_front(v);
		}

		///1. 判断图G是否有环
		hasCycle(n);
		printf(hascycle ? "YES\n" : "NO\n");

		///2. 判断图G是否为二分图
		checkTwoColor(n);
		printf(isTwoColorable ? "YES\n" : "NO\n");

		///3. 连通子图的个数及每个连通子图所包含的点(升序输出)
		printf("%d\n", count_connected_subgraph(n));
		for (int i = 1; i < count; ++i)
		{
			set<int>::iterator it;
			for (it = cc[i].begin(); it != cc[i].end(); ++it)
				printf("%d ", *it);
			printf("\n");
		}

		///4. 判断是否存在v到w的路径/求v到w的路径(保证v,w在范围内)
		while (k--)
		{
			scanf("%d%d", &v, &w);
			printpath(v, w);
		}

		///0. 初始化
		for (int i = 0; i < n; ++i)
			point[i].clear();
		printf("\n");
	}
	return 0;
}

待实现:欧拉回路
<think>嗯,用户想找DFS和BFS的实现模板。首先得确定他们需要的是基础的代码结构,可能是在准备面试或者学习算法。我需要先回忆一下这两种算法的基本框架。DFS通常用递归或者栈,而BFS用队列。根据用户提供的引用,比如引用[3]提到BFS的框架是起始点入队,循环处理队列,扩展队头元素。而DFS的话,引用[1]和[2]都提到DFS会尽可能深入,用递归或栈实现。 用户给的引用中有几个关键点,比如BFS的空间消耗较大,而DFS可能更节省空间但时间上可能有劣势。这些点可能在模板中体现出来。比如BFS需要用队列保存每一层的节点,而DFS递归时的隐式栈或者显式栈的结构。 需要确保模板代码正确,比如DFS的递归版本和迭代版本,BFS的标准队列操作。同时要注意注释说明,让用户明白每个步骤的作用。例如,在BFS模板中,是否需要标记已访问的节点?是的,特别是处理图的时候,避免重复访问。 然后,用户可能还需要一些注意事项,比如DFS在路径查找时的回溯步骤,或者BFS如何记录层数。引用[2]提到剪枝的重要性,这可能需要在模板之外进行优化,但模板本身应该保持简洁。 还要考虑不同应用场景下的变种,比如是否处理树或图的结构。例如,树的DFS可能不需要标记访问,但图的DFS必须标记,避免循环。因此,在模板中可能需要包含visited集合的部分。 最后,根据用户的要求,生成相关问题。可能需要围绕模板的使用、性能比较、应用场景来提问。例如,如何选择DFS和BFS,或者它们的时空复杂度分析。 总结下来,回答需要提供清晰的代码模板,区分递归和迭代实现,注明关键步骤,并附上相关问题帮助用户深入理解。</think>### DFS与BFS算法模板代码解析 #### 1. 深度优先搜索(DFS模板 DFS通过递归或栈实现“深度优先”特性,适用于路径查找、连通性检测等场景[^1]。 **递归实现模板**(以二叉树为例): ```python def dfs(node): if node is None: # 终止条件 return # 处理当前节点(例如打印或记录路径) print(node.val) # 递归访问相邻节点 dfs(node.left) dfs(node.right) ``` **迭代实现模板**(显式栈): ```python def dfs_iterative(root): stack = [root] visited = set() # 用于图结构防重复访问 while stack: node = stack.pop() if node not in visited: visited.add(node) # 处理当前节点 print(node.val) # 将子节点按反向顺序入栈(保证顺序正确) if node.right: stack.append(node.right) if node.left: stack.append(node.left) ``` #### 2. 广度优先搜索(BFS)模板 BFS通过队列实现“逐层扩展”特性,适用于最短路径、层级遍历等问题[^3]。 **标准模板代码**: ```python from collections import deque def bfs(root): queue = deque([root]) visited = set() # 用于图结构防重复访问 while queue: level_size = len(queue) for _ in range(level_size): # 按层处理(可选) node = queue.popleft() if node not in visited: visited.add(node) # 处理当前节点 print(node.val) # 将相邻节点加入队列 if node.left: queue.append(node.left) if node.right: queue.append(node.right) ``` #### 关键对比 | 特性 | DFS | BFS | |-----------|-------------------|-------------------| | 数据结构 | 栈(递归隐式栈/显式栈) | 队列 | | 空间复杂度 | $O(h)$(树的高度) | $O(w)$(树的宽度) | | 适用场景 | 路径存在性、拓扑排序 | 最短路径、层级遍历 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值