图的遍历

图的遍历

时空限制1000ms / 128MB

题目描述

给出N个点,M条边的有向图,对于每个点v,求A(v)表示从点v出发,能到达的编号最大的点。

输入输出格式

输入格式:

第1 行,2 个整数N,M。

接下来M行,每行2个整数Ui,Vi,表示边(Ui,Vi)。点用1,2,,N编号。

输出格式:

N 个整数A(1),A(2),,A(N)。

输入输出样例

输入样例: 
4 3
1 2
2 4
4 3
输出样例: 
4 4 3 4

说明

• 对于60% 的数据,1N,K≤10^3

• 对于100% 的数据,1N,M≤10^5


一开始以为是道dfs水题,结果忘了有环。。。。。。。最后写了个tarjan缩点加dfs。

然后看了一下他们的题解,发现可以反向建边,然后按编号从大到小dfs。。。。。。。。

#include<bits/stdc++.h>
#define N 100050
using namespace std;

struct ss
{
    int to,next;
};

ss edg[N];
int head[N];
int now_edge=0;

void addedge(int u,int v)
{
    edg[now_edge]=(ss){v,head[u]};
    head[u]=now_edge++;
}


int dfn[N],low[N],color[N],now_clock,now_color;
int Stack[N],top;

void tarjan(int x)
{
    dfn[x]=low[x]=++now_clock;
    Stack[top++]=x;
    
    for(int i=head[x];i!=-1;i=edg[i].next)
    {
        int v=edg[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[x]=min(low[x],low[v]);
        }
        else
        if(!color[v])low[x]=min(low[x],dfn[v]);
    }
    
    if(low[x]==dfn[x])
    {
    //    for(int i=1;i<=4;i++)printf("%d ",color[i]);
    //    printf("
");
        now_color++;
        while(Stack[top-1]!=x)
        {
            color[Stack[--top]]=now_color;
        }
        color[Stack[--top]]=now_color;
    }
}

int ans[N];
int max_point[N]={0};

int dfs(int x)
{
//    printf("%d
",x);
    if(ans[x])return ans[x];
    int Max=max_point[x];
    for(int i=head[x];i!=-1;i=edg[i].next)
    Max=max(Max,dfs(edg[i].to));
    
    return ans[x]=Max;
}

void init()
{
    memset(ans,0,sizeof(ans));
    memset(head,-1,sizeof(head));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(color,0,sizeof(color));
    now_edge=0;
    top=1;
    now_color=0;
    now_clock=1;
}
int a[N],b[N];

int main()
{
    int n,m;
    scanf("%d %d",&n,&m);
    init();
    for(int i=1;i<=m;i++)
    {
        scanf("%d %d",&a[i],&b[i]);
        addedge(a[i],b[i]);
    }

    for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
    
    memset(head,-1,sizeof(head));
    now_edge=0;
    
//    for(int i=1;i<=n;i++)printf("%d ",color[i]);
    
    for(int i=1;i<=m;i++)
    {
        if(color[a[i]]!=color[b[i]])addedge(color[a[i]],color[b[i]]);
    }
    
    for(int i=1;i<=n;i++)max_point[color[i]]=max(max_point[color[i]],i);
    
    for(int i=1;i<=n;i++)printf("%d%c",dfs(color[i]),i==n?'
':' ');
    return 0;
}
View Code(tarjan+dfs)
原文地址:https://www.cnblogs.com/tian-luo/p/9671236.html