反向建图的妙用:P3916 图的遍历

题目描述:

给出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

解题思路:

        求图中各结点能到达的最大结点,正向思路的话可以循环正向遍历结点,定义一个最大值变量记录该结点能到达的最大值结点,然后结合DFS遍历其所有能到达的结点,随时更新最大值变量,这是可行的。

        为了简化可以采取逆向思路,采用反向建图的方式做出逆向图,从最大结点n开始DFS,凡是能遍历的结点,其正向图总最大能到达结点就是n,将记录保存在数组中。之后从次大结点再开始DFS,直到填满记录数组。

代码实现:

#include <iostream>
using namespace std;
#define maxn 100001
int maxv[maxn];   //记录能到达的最大结点
int head[maxn];
int m, n, cnt;

class Edge
{
public:
    int to;
    int next;
};
Edge edge[maxn];

void InsertEdge(int u, int v)
{
    edge[cnt].to = v;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}

void CreateG()
{
    memset(head, -1, sizeof(head));
    cin >> n >> m;
    int u = 0, v = 0;
    for (int i = 0; i < m; i++)
    {
        cin >> u >> v;
        InsertEdge(v, u);
    }
}

void DFS(int v, int max)
{
    if (maxv[v])
    {
        return;
    }
    maxv[v] = max;
    for (int i = head[v]; i != -1; i = edge[i].next)
    {
        DFS(edge[i].to, max);
    }
}

int main()
{
    CreateG();
    for (int i = n; i > 0; i--)
    {
        DFS(i, i);
    }
    for (int i = 1; i <= n; i++)
    {
        cout << maxv[i] << " ";
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可惜浅灰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值