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

 

题意

有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;
}

 

posted @ 2019-10-29 20:29  HOLLAY  阅读(249)  评论(0编辑  收藏  举报