给出一个有向图,请判断给出的深度优先遍历序列是否合法。 例如对于如下的图
0 1 4 2 5 3 和 0 2 5 1 4 3 和 3 2 5 1 4 0 都是合法的DFS序列,但0 2 3 1 4 5则不是合法的DFS序列。
输入格式:
第一行给出顶点数 M 和边数 N,以空格分隔;顶点标号从 0 到 M−1。其中 M 不超过 100。 之后 N 行,每行按如下格式给出图中的各条边:
ID1 ID2
这表示从编号为ID1的顶点到编号为ID2的顶点的有向边。 之后一行给出整数 K,表示有 K 个序列待检验的序列。 接下来的 K 行,每行给出 M 个以空格分隔的整数表示DFS序列。
输出格式:
对于每一个待检验序列,输出 Yes 表示合法,No 表示不合法。
输入样例:
6 9
0 1
0 2
0 3
2 1
3 2
4 2
1 4
2 5
4 5
3
0 1 4 2 5 3
0 2 5 1 4 3
0 2 3 1 4 5
输出样例:
Yes
Yes
No
思路:
判断DFS序列是否合法,那就模拟DFS,一旦遇到仍有邻接边未被访问,但是序列下一个点并不是邻接点,则说明是不合法序列。
代码有些地方略显冗长,不过问题不大,见谅!
源码:
#include<stdio.h>
#include<stdlib.h>
#define MaxNum 101
typedef struct GraphNode * MyGraph;
struct GraphNode{
int Nv;
int Ne;
int Graph[MaxNum][MaxNum];
};
MyGraph create(int M,int N)
{
MyGraph G=(MyGraph)malloc(sizeof(struct GraphNode));
G->Nv=M;
G->Ne=N;
int i,j;
for(i=0;i<MaxNum;i++)
{
for(j=0;j<MaxNum;j++)
{
G->Graph[i][j]=0;
}
}
return G;
}
void Insert(MyGraph G,int v1,int v2)
{
G->Graph[v1][v2]=1;
}
int DFS(MyGraph G,const int *refer,int *Visited,int i)
{
int value=refer[i];
Visited[value]=1;
int j;int f;
int flag=1;
for(j=i+1;j<G->Nv;j++)
{
if(!Visited[refer[j]])
{
if(G->Graph[value][refer[j]])
{
flag=DFS(G,refer,Visited,j);
}
else
{
/*要判断是否refer[i]已经是孤立点
若不是孤立点,但是refer[i]和refer*[i]并不连通,说明错误*/
int t;
for(t=0;t<G->Nv;t++)
{
if(G->Graph[refer[i]][t]&&!Visited[t])flag=0;
}
}
if(!flag)break;
}
}
return flag;
}
int IsValid(MyGraph G,const int *refer,int *Visited)
{
int i;
int f=1;
for(i=0;i<G->Nv;i++)
{
if(!Visited[refer[i]])
{
f=DFS(G,refer,Visited,i);
}
if(f)continue;
else return 0;
}
return 1;
}
void JudgeDFS(MyGraph G,const int *refer)
{
int Visited[G->Nv]={0};
int flag;
flag=IsValid(G,refer,Visited);
if(flag)
printf("Yes\n");
else
printf("No\n");
}
int main()
{
int N,M;
scanf("%d%d",&M,&N);
MyGraph G=create(M,N);
int i;
int v1,v2;
for(i=0;i<N;i++)
{
scanf("%d%d",&v1,&v2);
Insert(G,v1,v2);
}
int n,j;
scanf("%d",&n);
int refer[G->Nv];
for(i=0;i<n;i++)
{
for(j=0;j<G->Nv;j++)
{
scanf("%d",&refer[j]);
}
JudgeDFS(G,refer);
}
return 0;
}