1008. Airline Routes (35)

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值