深度搜索之(加强版)序号

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_37806112/article/details/83988014

        在之前基本款代码里使用visited数组来区分顶点,也就是visited[x]==true表示x顶点已经访问过,visited[x]==false表示还没访问过x顶点。加强版中使用”颜色”来区分顶点,除此之外还给每个顶点都打上一个时间戳。

        

        一开始所有顶点都是白色的,白色代表顶点还没有被访问过。当我们第一次遍历到一个顶点x时,会把顶点x染成灰色。灰色代表该顶点x已经被访问过(调用过DFS(x)),但是还没有访问结束(DFS(x)退出回溯),当前正在遍历的顶点还是经过x到达的。如果顶点x的所有相连的顶点都访问过了,马上要退出DFS(x)向上一层回溯。我们会将x的颜色染成黑色。黑色代表这个顶点的遍历已经结束,之后我们再也不会访问这个顶点。上面这个图就是我们已经遍历了1->2->3->4,并且在4号顶点发现无路可走,回溯到3号顶点时的状态。123是灰色,4是黑色,56是白色。

以上图为例,有颜色标记和时间戳的DFS的过程:

                                                    

 注:红色的边表示沿着这条边到达了一个白色的顶点,也就是还未遍历到的新顶点。虚线边表示沿着这条边到达了一个灰色节点。黑色边表示当前顶点已经遍历结束,沿着之前的红色边回溯到上一个顶点。

         DFS的时间戳是很有意思的。如果我们把每个顶点的时间戳看成区间,左端点是D(x),右端点是F(x),那么这些区间会有像括号一样的嵌套关系,如下图:

                                      

       我们可以看出来任意两个顶点的区间只可能有2种关系:(1)两个区间相离;(2)一个区间包含另一个区间。换句话说,不会出现像[1, 10], [4, 13]这样两个区间互相跨立的情况。这种关系可以形象的看成是一个匹配合法的括号序列。

真题演练:

               

#include<iostream>
#include<vector>
using namespace std;

int n, q,ts=0;
vector<int> g[100001];
int d[100001], f[100001];
void dfs(int x)
{
	ts++;
	d[x] = ts;
	for (int i = 0; i <(g[x].size());i++)
	{
		int y = g[x][i];
		dfs(y);
	}
	ts++;
	f[x] = ts;
}
int main()
{
	cin >> n >> q;
	for (int i = 2; i <= n;i++)
	{
		int u, v;
		cin >> u >> v;
		//父版本号知道子版本号
		g[u].push_back(v);
	}
	dfs(1);
	while (q--)
	{
		int x, y;
		cin >> x >> y;
		if (d[x]<=d[y] && f[x]>=f[y])
		{
			cout << "YES" << endl;
		}
		else
		{
			cout << "NO" << endl;
		}
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_37806112/article/details/83988014