PTA习题解析——判断DFS序列的合法性

情景需求

测试数据

输入样例

6 9
0 1
0 2
0 3
2 1
3 2
4 2
1 4
2 5
4 5
4
0 1 4 2 5 3
0 2 5 1 4 3
0 2 3 1 4 5
3 2 5 1 4 0

输出样例

Yes
Yes
No
Yes

情景解析

也就是说,对于顶点而言我们并不关心顶点的顺序,因为这是一个一对多的关系,我们没有手法去强行规定他们的先后序。因此对于图结构的 DFS,可能会产生不只一个的结果序列,例如从 0 号顶点出发,“ 0 1 4 2 5 3 ” 和 “ 0 2 5 1 4 3 ”都可以认为是正确的序列。
从上文所述,我们明白了这道题是不能够直接去 DFS 得到序列进行单模匹配的,也就是说不能用单纯的验证法去证明序列的正误。什么样的思路是可行的?正着做不行那就反着来,用反证法来实现,即我假设给出的序列是正确的,那么我按照你的序列来遍历应当是正确的,如果能够完成遍历那就说明序列正确,若在任何一个地方发生错误以至于无法 DFS,那就说明序列错误。
根据分析,我称之为“定向的 DFS”,即我虽然是按照 DFS 的模式去找这个序列,但是我的操作是受限的——根据给出的顺序遍历。因此我根据往下深度搜索时需要把已知的序列传递下去,为了使得提取边的信息更为方便,我选择邻接矩阵来存储图结构。

注意事项

由于要模拟 DFS,我们还是要使用递归,由于数据是受限的,因此递归的接口的正确性需要保证。这里给出 2 个卡了我 4 天的关键点:

  1. 由于图可能是非连通图,因此在最外层还需要加一个循环,放置单个路径挖掘完毕后,后续还有一个独立开来的图结构;
  2. 递归 DFS 就免不了回溯,此时必须保证回溯的接口的各个参数都是正确的,否则一旦遇到稠密图需要回溯时,可能就会因为参数的错误访问了不该访问的结点。

模拟验证

Yes 样例

假设验证序列 “ 0 1 4 2 5 3 ”,首先我们进入顶点 0:

根据序列,接下来我要去找顶点 1,路径可走:

根据序列,接下来我要去找顶点 4,路径可走:

根据序列,接下来我要去找顶点 2,路径可走:

根据序列,接下来我要去找顶点 5,路径可走:

根据序列,接下来我要去找顶点 3,路径不存在,这是由于顶点 5 没有指向其他顶点导致的。这个时候我们就回溯




我们发现,回溯到 0 号顶点时,有路径通向 3 号顶点,遍历继续。

经检验,该 DFS 序列正确。

No 样例

假设验证序列 “ 0 2 3 1 4 5 ”,我们跳到第二步:

根据序列,接下来我要去找顶点 3,路径不存在。但是这个时候,顶点 2 是存在向下深度搜索的路径的,分别是“ 2->1 ” 和 “ 2->5 ”,这就说明了序列是错误的。

代码实现

judgeDFS 函数

伪代码

该函数是个递归函数,用于执行所谓的“定向的 DFS”,同时兼具判断合法性的功能。

代码

bool judgeDFS(MGraph& g, int dfs[], int idx)
{
	bool flag = true;

	visited[dfs[idx]] = 1;
	if (idx == g->n - 1)
	{
		return true;
	}
	for (int i = idx + 1; i < g->n; i++)
	{
		if (visited[dfs[i]] == 0)
		{
			if (g->edges[dfs[idx]][dfs[i]] == 1)
			{
				flag = judgeDFS(g, dfs, i);
			}
			else
			{
				for (int j = 0; j < g->n; j++)
				{
					if (g->edges[dfs[idx]][j] == 1 && visited[j] == 0)
					{
						flag = false;
					}
				}
			}
			if (flag == false)
			{
				break;
			}
		}
	}
	return flag;
}

主函数

#include <iostream>
using namespace std;
//图的邻接矩阵	
#define  MAXV  101
typedef struct    //图的定义
{
	int edges[MAXV][MAXV];    //邻接矩阵
	int n, e;    //顶点数,弧数
} *MGraph, GraphNode;    //图的邻接矩阵表示类型
int visited[MAXV];
void CreateMGraph(MGraph& g, int n, int e);    //建图 
bool judgeDFS(MGraph& g, int dfs[], int idx);

int main()
{
	MGraph g;
	int n, e, fre;
	int j;
	int dfs[MAXV];
	bool flag = true;

	cin >> n >> e;
	CreateMGraph(g, n, e);
	cin >> fre;
	for (int i = 0; i < fre; i++)
	{
		for (j = 0; j < n; j++)
		{
			cin >> dfs[j];
			visited[j] = 0;
		}
		for (j = 0; j < n; j++)
		{
			if (visited[dfs[j]] == 0)
			{
				flag = judgeDFS(g, dfs, j);
			}
			if (flag == false)
			{
				break;
			}
		}
		if (flag == true)
		{
			cout << "Yes" << endl;
		}
		else
		{
			cout << "No" << endl;
		}
	}
	return 0;
}
posted @ 2020-04-27 17:03  乌漆WhiteMoon  阅读(843)  评论(0编辑  收藏  举报