1 条题解

  • 0
    @ 2026-6-13 21:41:47

    // SCC 缩点 Tarjan 算法 O(N)
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=250005,M=4*N;
    int to[M],ne[M],h[N],idx;
    void add(int a,int b){
      to[++idx]=b,ne[idx]=h[a],h[a]=idx;
    }
    int n,m,a[505][505];
    int dfn[N],low[N],stk[N],top,scc[N],cnt;
    int in[N],out[N],s1,s2;
    
    int get(int i,int j){return (i-1)*m+j;} //格点的编号
    void ade(int i,int j){
      if(i>1){
        if(a[i][j]>=a[i-1][j]) add(get(i,j),get(i-1,j)); //向上连边
        if(a[i][j]<=a[i-1][j]) add(get(i-1,j),get(i,j)); //向下连边
      }
      if(j>1){
        if(a[i][j]>=a[i][j-1]) add(get(i,j),get(i,j-1)); //向左连边
        if(a[i][j]<=a[i][j-1]) add(get(i,j-1),get(i,j)); //向右连边
      }
    }
    
    void tarjan(int x){ //SCC缩点
      dfn[x]=low[x]=++dfn[0]; stk[++top]=x;
      for(int i=h[x];i;i=ne[i]){
        int y=to[i];
        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; //缩点的编号
      }
    }
    
    int main(){
      scanf("%d%d",&m,&n); //m列n行
      for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)
        scanf("%d",&a[i][j]),ade(i,j); //连边
        
      for(int i=1;i<=n*m;++i) if(!dfn[i]) tarjan(i); 
      
      for(int i=1;i<=n*m;++i)for(int j=h[i];j;j=ne[j]) //枚举每个格点的出边
        if(scc[i]!=scc[to[j]]) ++in[scc[to[j]]],++out[scc[i]];
        
      for(int i=1;i<=cnt;++i){
        if(!in[i]) ++s1;  //入度为0的缩点个数
        if(!out[i]) ++s2; //出度为0的缩点个数
      }
      printf("%d",cnt==1?0:max(s1,s2));
      return 0;
    }
    
    • 1

    D158 SCC 缩点[USACO04DEC] Cow Ski Area G

    信息

    ID
    2184
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    3
    已通过
    2
    上传者