• 洛谷P3436


    直接说解法。

    首先可以发现,如果图中出现环,就会出现无数条路径,因为我们可以在环里走无数圈来增加路径数量。

    所以我们可以缩点处理环,顺便处理环上点的个数。

    然后对于非环上的点,可以在重建图后用拓扑排序简单 DP 来统计每个点到终点的路径总数。特别的,为了方便统计,我们可以把路径总数超出范围的点(包括环上的点)直接赋值为 (36500)

    然后统计输出,就做完了。

    void add(int fr,int to){
      e[++tot]=(edge){fr,to,head[fr]};
      head[fr]=tot;
    }
    
    void Add(int fr,int to){
      E[++TOT]=(edge){fr,to,Head[fr]};
      Head[fr]=TOT;  
    }
    
    void tarjan(int u){
      dfn[u]=low[u]=++cnt;
      vis[u]=1;zhan[++top]=u;
      for(int i=head[u];i;i=e[i].nxt){
        int to=e[i].to;
        if(!dfn[to]) tarjan(to),low[u]=min(low[u],low[to]);
        else if(vis[to]) low[u]=min(low[u],dfn[to]);
      }
      if(dfn[u]==low[u]){
        ++siz[++t];
        int pre=zhan[top--];
        num[pre]=t;vis[pre]=0;
        while(pre!=u){
          ++siz[t];
          pre=zhan[top--];
          num[pre]=t;vis[pre]=0;
        }
      }
    }
    
    void topsort(){
      queue<int> q;
      for(int i=1;i<=t;i++)
        if(!du[i]) q.push(i);
      while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=Head[u];i;i=E[i].nxt){
          int to=E[i].to;
          if(--du[to]==0) q.push(to); 
          if(flag[u]) flag[to]=1;dp[to]+=dp[u];
          if(siz[to]>1&&flag[to]) dp[to]=UP;
          if(dp[to]>UP) dp[to]=UP;
        }
      }
    }
    
    signed main(){
      n=read();m=read();
      for(int i=1;i<=m;i++){
        fr[i]=read(),to[i]=read();
        add(to[i],fr[i]);
      }
      for(int i=1;i<=n+1;i++) if(!dfn[i]) tarjan(i);
      
      for(int i=1;i<=m;i++){
        if(fr[i]==to[i]) ++siz[num[fr[i]]];
        else if(num[fr[i]]!=num[to[i]]) 
          Add(num[to[i]],num[fr[i]]),du[num[fr[i]]]++;
      }
      
      flag[num[n+1]]=1;
      dp[num[n+1]]=1;topsort();
      for(int i=1;i<=n;i++){
        if(!flag[num[i]]) continue;
        ans=max(ans,dp[num[i]]);
      }
      for(int i=1;i<=n;i++){
        if(!flag[num[i]]) continue;
        all+=(dp[num[i]]==ans);
      }
      if(ans==UP) puts("zawsze");
      else printf("%d
    ",ans);printf("%d
    ",all);
      for(int i=1;i<=n;i++){
        if(!flag[num[i]]) continue;
        if(dp[num[i]]==ans) printf("%d ",i);
      }
      return 0;
    }
    
  • 相关阅读:
    Java锁---偏向锁、轻量级锁、自旋锁、重量级锁
    Java自旋锁
    设计模式的原则
    CGLIB介绍与原理(通过继承的动态代理)
    Android Messenger
    Android AIDL的用法
    长连接和短连接和推送
    Java对称加密算法
    Android 热修复技术中的CLASS_ISPREVERIFIED问题
    Java类加载器
  • 原文地址:https://www.cnblogs.com/KnightL/p/15480918.html
Copyright © 2020-2023  润新知