Cow Traffic(正反向建图+DAG拓扑排序)

本文介绍了一种解决特定图论问题的方法:在有向无环图(DAG)中,通过两次拓扑排序计算从任意起点到固定终点路径中经过次数最多的一条边。文章详细解释了算法原理,包括正反向建图和乘法原理的应用,并提供了完整的代码实现。
摘要由CSDN通过智能技术生成

 

题意

有N(1<=N<=5000)个点,m条边(1<=M<=50000)。起点可以是任何一个入度为0的点,终点是N。求从起点到终点的所有路中,经过次数最大的一条路。输出经过次数。(规定每个点需要连接到编号更大的点,且不存在循环)

题解

该图为DAG(有向无环图),可利用拓扑排序,正反向建图分别进行两次拓扑排序。

根据乘法原理,在一条边M(u->v)上,通过边M的次数为从源点到达u的方式数量×从终点到达v的方式数量。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
struct node{
    int to,next;
}edge1[50005],edge2[50005];
int n,m;
int cnt1,head1[5005],indegree1[5005],num1[5005];
int cnt2,head2[5005],indegree2[5005],num2[5005];
void add(int u,int v)
{
    /*正向建图*/
    edge1[cnt1].to=v;
    edge1[cnt1].next=head1[u];
    head1[u]=cnt1++;

    /*反向建图*/
    edge2[cnt2].to=u;
    edge2[cnt2].next=head2[v];
    head2[v]=cnt2++;
}
void topoSort1()//对正向图进行拓扑排序
{
    queue<int>q;
    for(int i=1;i<=n;i++){
        if(!indegree1[i]){ 
            q.push(i);//入度为0的点入队
            num1[i]=1;
        }
    }
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int j=head1[x];~j;j=edge1[j].next){
            indegree1[edge1[j].to]--;
            num1[edge1[j].to]+=num1[x];//记录该点的正向总入度
            if(!indegree1[edge1[j].to])
                q.push(edge1[j].to);
        }
    }
}
void topoSort2()//对反向图进行拓扑排序
{
    queue<int>q;
    for(int i=1;i<=n;i++){
        if(!indegree2[i]){
            q.push(i);
            num2[i]=1;
        }
    }
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int j=head2[x];~j;j=edge2[j].next){
            indegree2[edge2[j].to]--;
            num2[edge2[j].to]+=num2[x];//记录该点的反向总入度
            if(!indegree2[edge2[j].to])
                q.push(edge2[j].to);
        }
    }
}
int main()
{
    int u,v;
    while(~scanf("%d%d",&n,&m)){
        cnt1=0,cnt2=0;
        memset(indegree1,0,sizeof(indegree1));
        memset(indegree2,0,sizeof(indegree2));
        memset(head1,-1,sizeof(head1));
        memset(head2,-1,sizeof(head2));
        memset(num1,0,sizeof(num1));
        memset(num2,0,sizeof(num2));
        for(int i=1;i<=m;i++){
            scanf("%d%d",&u,&v);
            indegree1[v]++;//记录正向图各点的入度
            indegree2[u]++;//记录反向图各点的入度
            add(u,v);
        }
        topoSort1();
        topoSort2();
        int ans=0;
        for(int i=1;i<=n;i++){ 
            for(int j=head1[i];~j;j=edge1[j].next){ //枚举每一条边
                ans=max(ans,num1[i]*num2[edge1[j].to]);//(u->v)u点正向总入度和v点反向总入度的乘积,更新答案最大值
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值