D159 SCC 缩点+拓扑 Tarjan 算法 P3119 [USACO15JAN] Grass Cownoisseur G

D159 SCC 缩点+拓扑 Tarjan 算法 P3119 [USACO15JAN] Grass Cownoisseur G_哔哩哔哩_bilibili

 

P3119 [USACO15JAN] Grass Cownoisseur G - 洛谷

n 个点 m 条有向边的有环图,从 1 号点出发,路径最多翻转一条边,回到 1 号点,求经过的最多点数(点不重复计数)。

思路

先跑 Tarjan 缩点,同时记录每个缩点的点数 siz[]

设 1 号点所在缩点的编号为 s,用 d 数组记录路径上点的数量

对缩点建正图,拓扑求从 s 到各点的最长路 d1[]

对缩点建反图,拓扑求从 s 到各点的最长路 d2[]

注意,s 点可能不是入度为 0 的点,要把所有点 d 值初始化为 0,把 d[s] 初始化为 siz[s],只更新从 s 能到的点的 d 值

样例建图,2,4,7 缩成一个点,缩点图应该重新编号的,我用原始点方便观察

image

最后,枚举每条边的端点,满足正图能到 y 且 反图能到 x,说明有向边 $(x,y)$ 是可以翻转的,就拼接路径,更新答案

   $ans=max\{ \;d1[scc[y]]+d2[scc[x]]-siz[s] \;\}$,因为 1 号点的 $siz$ 算了两次

相关板子:

D15【模板】SCC 缩点 Tarjan 算法 - 董晓 - 博客园

 

// SCC 缩点 Tarjan 算法 O(N)
#include<bits/stdc++.h>
using namespace std;

const int N=100005;
vector<int> e[N],e1[N],e2[N];
int n,m,ans;
int dfn[N],low[N],stk[N],top,scc[N],siz[N],cnt;
int d1[N],d2[N];

void tarjan(int x){ //SCC缩点
  dfn[x]=low[x]=++dfn[0]; stk[++top]=x;
  for(auto y:e[x]){
    if(!dfn[y]) tarjan(y),low[x]=min(low[x],low[y]);
    else if(!scc[y]) low[x]=min(low[x],dfn[y]); 
  }

  if(dfn[x]==low[x]){
    ++cnt;
    while(stk[top+1]!=x) scc[stk[top--]]=cnt,siz[cnt]++;
  }
}
int main(){
  scanf("%d%d",&n,&m);
  for(int a,b;m--;) scanf("%d%d",&a,&b),e[a].push_back(b);
  
  for(int i=1;i<=n;++i)if(!dfn[i])tarjan(i); //SCC缩点

  for(int x=1; x<=n; x++)for(auto y:e[x]){ //枚举原始点的邻接点
    int a=scc[x],b=scc[y];
    if(a!=b) e1[a].push_back(b); //对缩点建正图
    if(a!=b) e2[b].push_back(a); //对缩点建反图
  }
  
  int s=scc[1]; //1号点做起点
  d1[s]=siz[s]; //起点自身可达
  for(int x=cnt; x; x--)for(auto y:e1[x]) //枚举缩点的邻接点
    if(d1[x]) d1[y]=max(d1[y],d1[x]+siz[y]); //正图从s到各点的最长路d1[]
  
  d2[s]=siz[s]; //起点自身可达
  for(int x=1; x<=cnt; x++)for(auto y:e2[x]) //枚举缩点的邻接点
    if(d2[x]) d2[y]=max(d2[y],d2[x]+siz[y]); //反图从s到各点的最长路d2[]
  
  ans=siz[s]; //从s出不去的情况
  for(int x=1; x<=n; x++)for(auto y:e[x]){ //枚举原始点的邻接点
    if(d1[scc[y]] && d2[scc[x]]) //正图能到y且反图能到x
      ans=max(ans,d1[scc[y]]+d2[scc[x]]-siz[s]); //拼接时s点算了两次
  }
  printf("%d\n",ans);
}

 

posted @ 2026-05-19 10:06  董晓  阅读(60)  评论(0)    收藏  举报