有向带环图的各种遍历处理

有向带环图的各种遍历处理_第1张图片

防坑大招:先上一张母上大人设计的有向有环图,作为测试数据,(见附图)

要求:找到所有能到达4的节点x,can[x]数组中置对应值为1

自环

建边时,通过x!=y, 将自环边直接滤掉

for(int i=1;i<=m;i++)
    {
        int x,y;scanf("%d%d",&x,&y);
        if(x!=y) {v[x].push_back(y);p[y].push_back(x);}
    } 

反向DFS,OK

从终点t出发能到达的节点,此时t相当于根,等同于:以t为出发点,判断有向图的连通性。

反向建图,采用有向图的DFS遍历,所能达到的点构成一颗生成树。

   for(int i=1;i<=m;i++)
    {
        int x,y;scanf("%d%d",&x,&y);
        if(x!=y) {v[x].push_back(y);p[y].push_back(x);}    //y-x,建反图
    } 
    scanf("%d%d",&s,&t);can[t]=1;
    find(t);                               //从终点开始遍历


void find(int x)
{
    vis[x]=1;can[x]=1;                      //先置can标志,代表从该节点可以到达终点
    for(int i=0;i

正向DFS,无法正确处理

正向DFS遍历判断连通性,代表从起点所能达到节点,需要遍历结束才能确认是否能达到终点t,再由t回溯时向前置can标志。

在DFS结束后置can标志,如果某点的孩子can,则它的父亲也can.

但是,can数组不对!遍历时每个节点按DFS序走,不能重复走!

成环的节点必然会重复走。比如:图中的2-3-2-4, 3节点可到达4,但必须二次经过2才可以!

for(int i=1;i<=n;i++) if(!vis[i]) find(i); //main函数

void find(int x)
{
    vis[x]=1;
    if(x==t) return;
    for(int i=0;i

环,重复走节点

图中2-3-2,   3-13-3,2-5-6-2、6-7-8-7等,节点2、3、6等重复走。

引入out数组,计算每个节点的出度,只有还有边可走,就继续,不管该节点有没有访问过。

for(int i=1;i<=m;i++)
{
        int x,y;scanf("%d%d",&x,&y);
        if(x!=y) {v[x].push_back(y);out[x]++;p[y].push_back(x);}  //读边时计算出度out
 } 

   
for(int i=1;i<=n;i++) if(!vis[i]) find(i);

void find(int x)
{
    vis[x]=1;
    if(x==t) return;
    for(int i=0;i0||!vis[v[x][i]]) {out[x]--;find(v[x][i]);} //加入out判断,--
        if(can[v[x][i]]) can[x]=1;
    }
}

此种写法相当于欧拉通路的判断,每个边走一次

然后栈中的点都是可以到达的,弹栈置can数据值

然而,还不如直接用欧拉通路的算法更简洁。。。

void dfs(int i)
{
	for (int j=0; j

环,重复走边

1-9-2-10-9-2-4,  9-2边重复走。其实,也相当于有割边唉~~~

边允许重复走,top数据不起作用。尝试清除vis[]标志,允许重复走。结果可以,没有WA,但TLE!

多次扫描,效率太低~~

void find(int x)
{
    if(x==t) return;
    if (can[v[x][i]]==1) return;   //剪枝
    for(int i=0;i

visit[]数组访问标志多值,代表N次不同进入

visit[x]=0,1,2...          其中:>=2代表多次访问,成环;

此方法一般用于判断是否有环,简单环

然而。。。只有40分

void find(int x)
{
    vis[x]++;
    for(int i=0;i

 

Tarjan强连通分量

先缩点,按有向无环图遍历。

对于同一个连通分量中的点,只要有一个点到达,则连通分量中所有点全可以到达。

void tarjan(int x)
{
	sa.push(x);ins[x]=1;
	dfn[x]=low[x]=++indexs;
	for(int i=0;i

交上去AC掉了,还行,跑的挺快。除了代码量较大别的都很完美。

有向带环图正向DFS的终极大法!!!

 

 

 

 

你可能感兴趣的:(有向带环图的各种遍历处理)