zoukankan      html  css  js  c++  java
  • 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
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    面向对象的继承关系体现在数据结构上时,如何表示
    codeforces 584C Marina and Vasya
    codeforces 602A Two Bases
    LA 4329 PingPong
    codeforces 584B Kolya and Tanya
    codeforces 584A Olesya and Rodion
    codeforces 583B Robot's Task
    codeforces 583A Asphalting Roads
    codeforces 581C Developing Skills
    codeforces 581A Vasya the Hipster
  • 原文地址:https://www.cnblogs.com/HOLLAY/p/11761350.html
Copyright © 2011-2022 走看看