zoukankan      html  css  js  c++  java
  • tarjan求强连通+缩点——cf1248E

    这题好像是DEF里最水的,,

    /*
    建图:如果a认识b,那么从a->b连一条边,将点分成两个集合A,B,没有从A->B的边 
    求出强连通分量,再造一张新图,新图中任取一个的出度为0的点作为集合A即可
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define N 2000005
    
    struct Edge{int to,nxt;}e[N<<1];
    int head[N],tot,n,m;
    
    int c[N],out[N],cnt;//新图的点个数,每个点的出度 
    int ind,dfn[N],low[N],stk[N],top,ins[N];
    void tarjan(int x){
        dfn[x]=low[x]=++ind;
        stk[++top]=x;ins[x]=1;
        for(int i=head[x];i!=-1;i=e[i].nxt){
            int y=e[i].to;
            if(!dfn[y]){
                tarjan(y);
                low[x]=min(low[x],low[y]);
            }
            else if(ins[y])
                low[x]=min(low[x],dfn[y]);
        }
        if(dfn[x]==low[x]){
            cnt++;
            int y;
            do{
                y=stk[top--];
                ins[y]=0;
                c[y]=cnt;
            }while(x!=y);
        }
    }
    
    void init(){
        cnt=tot=ind=0;
        for(int i=0;i<=2*n;i++)
            low[i]=dfn[i]=ins[i]=out[i]=c[i]=0,head[i]=-1;
    }
    void add(int u,int v){
        e[tot].to=v;e[tot].nxt=head[u];head[u]=tot++;
    }
    
    int main(){
        int t;cin>>t;while(t--){
            cin>>n>>m;
            init();
            for(int i=1;i<=m;i++){
                int u,v;scanf("%d%d",&u,&v);
                if(u!=v)add(u,v);    
            }
            
            for(int i=1;i<=n;i++)
                if(!dfn[i])tarjan(i);
            
             for(int u=1;u<=n;u++)
                for(int i=head[u];i!=-1;i=e[i].nxt){
                    int v=e[i].to;
                    if(c[u]!=c[v])
                        out[c[u]]++;
                }
                
            int ans=0;
            for(int i=1;i<=cnt;i++)
                if(out[i]==0){ans=i;break;}
            if(ans==0||cnt==1){puts("No");continue;}
            
            puts("Yes");
            int cnta=0,cntb=0;
            for(int i=1;i<=n;i++)
                if(c[i]==ans)cnta++;
                else cntb++;
            cout<<cnta<<" "<<cntb<<'
    ';
            for(int i=1;i<=n;i++)if(c[i]==ans)cout<<i<<" ";puts("");
            for(int i=1;i<=n;i++)if(c[i]!=ans)cout<<i<<" ";puts("");
        }
    }
    /*
    9 21
    1 7
    5 7
    4 8
    1 1
    4 4
    7 3
    3 3
    6 3
    6 6
    5 5
    7 7
    8 2
    9 2
    3 1
    8 8
    9 9
    2 2
    1 5
    6 7
    2 6
    6 4
    
    */
  • 相关阅读:
    在过滤器中验证接口中的Token
    导出EXCEL的 两个方法
    调用webservice接口,返回xml(String)转义
    时间类的操作
    jvm 内存解析以及jvm调优
    redis springMVC 配置与应用
    题目2 成绩排序
    题目1 排序
    题目1042:Coincidence
    题目1131:合唱队形
  • 原文地址:https://www.cnblogs.com/zsben991126/p/11741372.html
Copyright © 2011-2022 走看看