PAT上的一道题,题目意思是给定一个有向图,判断给定两个顶点间是否有回路。若两个顶点在同一个强连通图上,那么他们之间肯定是有回路的。之前没有遇到过计算强连通图分支的问题。计算一个有向图的强连通图分支的方法是进行两次深度优先遍历。第一次在原图上进行深度优先遍历。第二次在原图的反向图上进行深度优先遍历。
深度优先遍历的方法:
一个顶点有相关的3个变量f(访问该顶点结束时间:即从该节点向下访问结束时的时间),和一个祖先顶点变量r(若从v到u有一条边,当访问到v时,再访问u时,r(u)=v)和颜色标记c,若顶点v已经被访问c,c(v) = 2(黑色),若顶点v正在访问,c(v)=1(灰色),若顶点v未被访问到c(v)=0(白色)。遍历的过程如下:
没次从顶点集中寻找一个白色v顶点,以该顶点作为深度优先搜索树根节点开始,进行一次深度优先搜索。之后从v开始,递归如下过程:v颜色设为1,访问时间+1,对v的邻接表的每一个白色节点u,r(u)=v,然后从u继续访问。当从某节点i退出访问时c(i)设为2,f(i)设置为当前访问时间。
第一访问得到的点按照访问结束时间降序排序,以此为顺序在原图的反向图上再进行一次深度优先遍历。得到各个点的祖先顶点集合r集。在r集上做并查集即可得到各个强连通图。
代码如下:
#include<vector>
#include<queue>
#include<algorithm>
#include<stdio.h>
using namespace std;
struct Vertex{
int id,color,finish,root;
bool operator < (Vertex const & a)const{
return finish>a.finish;
}
};
void DFS(vector<vector<int>>& AdjCity,vector<Vertex>&vers,vector<int>&visitSort);
void DFSVisit(int st,vector<vector<int>>&AdjCity,vector<Vertex> &vers,int &time)
{
vers[st].color = 1;
++time;
for(int i=0;i<AdjCity[st].size();++i)
{
if(vers[AdjCity[st][i]].color==0)
{
vers[AdjCity[st][i]].root=st;
DFSVisit(AdjCity[st][i],AdjCity,vers,time);
}
}
vers[st].color = 2;
vers[st].finish=++time;
}
void DFS(vector<vector<int>>& AdjCity,vector<Vertex>&vers,vector<int>&visitSort)
{
int time = 0;
for(int i=0;i<visitSort.size();++i)
{
if(vers[visitSort[i]].color==0)
DFSVisit(vers[visitSort[i]].id,AdjCity,vers,time);
}
}
int findroot(vector<Vertex>&vers,int x)
{
if(vers[x].root==-1) return x;
int r = findroot(vers,vers[x].root);
vers[x].root=r;
return r;
}
void func(vector<Vertex> &vers,vector<int> &visitSort)
{
vector<Vertex> vtmp=vers;
sort(vtmp.begin()+1,vtmp.end());
for(int i=1;i<vers.size();++i)
{
visitSort[i-1]=vtmp[i].id;
vers[i].color=vers[i].finish = 0;
vers[i].root = -1;
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
vector<vector<int>> AdjCity0(n+1);
vector<vector<int>> AdjCity1(n+1);
vector<Vertex> vers(n+1);
for(int i=0;i<=n;++i)
{
vers[i].id=i;
vers[i].color=0;
vers[i].finish=0;
vers[i].root = -1;
}
for(int i=0;i<m;++i)
{
int st,en;
scanf("%d%d",&st,&en);
AdjCity0[st].push_back(en);
AdjCity1[en].push_back(st);
}
vector<int> visitSort(n);
for(int i=0;i<n;++i)
{
visitSort[i]=i+1;
}
DFS(AdjCity0,vers,visitSort);
func(vers,visitSort);
DFS(AdjCity1,vers,visitSort);
int k;
scanf("%d",&k);
vector<bool> ans;
for(int i=0;i<k;++i)
{
int st,en;
scanf("%d%d",&st,&en);
int r1 = findroot(vers,st);
int r2 = findroot(vers,en);
ans.push_back(r1==r2);
}
for(int i=0;i<ans.size();++i)
{
if(ans[i]==true) printf("Yes\n");
else printf("No\n");
}
return 0;
}