Loading

洛谷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\n",ans);printf("%d\n",all);
  for(int i=1;i<=n;i++){
    if(!flag[num[i]]) continue;
    if(dp[num[i]]==ans) printf("%d ",i);
  }
  return 0;
}
posted @ 2021-10-29 16:01  KnightL  阅读(39)  评论(0编辑  收藏  举报