• 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;
    }
  • 相关阅读:
    JUnit5依赖注入与测试接口
    Python如何设计面向对象的类(下)
    JUnit5参数化测试的几种方式
    JUnit5的条件测试、嵌套测试、重复测试
    熬夜肝了一份 C++/Linux 开发学习路线
    适合普通大学生的 Java 后端开发学习路线
    二本,拿腾讯,阿里 offer 了
    适合普通大学生的前端学习路线
    41道计算机网络高频面试题(附带答案)
    在Rancher中修改K8S服务参数的万金油法则
  • 原文地址:https://www.cnblogs.com/HOLLAY/p/11761350.html
Copyright © 2020-2023  润新知