• Wannafly14挑战赛 C(tarjan缩点)题解


    题目:牛客题目链接

    思路:这道题有点像这道题

    先缩点,缩完之后判断一下整个强连通分量入度是不是0,如果是的话向ans压入该强连通分量最小的那个值。最后排序一下ans输出就行了。

    思路一下就想到了,就是写的有点迷,WA了好几发,加点注释...

    炜神tql...果然我还是菜鸡,水题切的贼慢orz

    代码:

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<queue>
    #include<cmath>
    #include<string>
    #include<map>
    #include<stack> 
    #include<set>
    #include<vector>
    #include<iostream>
    #include<algorithm>
    #include<sstream>
    #define ll long long 
    const int N=1e5+5;
    const ll INF=1e5+5;
    using namespace std;
    int n,m,cnt;
    map<int,int> vis;
    set<int> o;
    vector<int> g[N],check,ans,in[N];    //in记录的是指向i的点,在后面用来判断
    stack<int> s;
    int dfn[N],low[N];
    void tarjan(int x){
    	dfn[x]=low[x]=++cnt;
    	s.push(x);
    	vis[x]=1;
    	for(int i=0;i<g[x].size();i++){
    		int v=g[x][i];
    		if(!dfn[v]){
    			tarjan(v);
    			low[x]=min(low[x],low[v]);
    		}
    		else if(vis[v]){
    			low[x]=min(low[x],dfn[v]);
    		}
    	}
    	o.clear();    //用来查询scc的点
    	if(dfn[x]==low[x]){
    		int a;
    		check.clear();
    		while(true){
    			a=s.top();
    			s.pop();
    			vis[a]=0;
    			check.push_back(a);	//记录这个强通量所有点 
    			o.insert(a);	//记录这个强通量所有点,在后面用来查找 
    			if(a==x) break;
    		}
    		int flag=0;
    		for(int i=0;i<check.size();i++){	//排查每个in 
    			int p=check[i];
    			for(int j=0;j<in[p].size();j++){
    				if(o.count(in[p][j])!=true){	//这个点不属于同一scc,说明整个scc有入度,不是我们要找的
    					flag=1;
    					break;
    				}
    			}
    			if(flag) break;	
    		}
    		if(flag==0){	//整个scc入度为0
    			sort(check.begin(),check.end());
    			ans.push_back(check[0]);    //只需要最小的那个就行了
    		}
    	}
    	
    }
    void init(){ 
    	cnt=0;
    	ans.clear();
    	vis.clear();
    	memset(dfn,0,sizeof(dfn));
    	memset(low,0,sizeof(low));
    	while(s.size()!=0) s.pop();
    	for(int i=0;i<N;i++){
    		in[i].clear();
    		g[i].clear();
    	}
    }
    int main(){
    	init();
    	int u,v;
    	scanf("%d%d",&n,&m);
    	for(int k=0;k<m;k++){
    		scanf("%d%d",&u,&v);
    		g[u].push_back(v);
    		in[v].push_back(u);
    	}
    	for(int i=1;i<=n;i++){
    		if(!dfn[i]) tarjan(i);
    	}
    	sort(ans.begin(),ans.end()); 
    	cout<<ans.size()<<endl;
    	for(int i=0;i<ans.size();i++){
    		if(i!=0) printf(" ");
    		cout<<ans[i];
    	}
        return 0;
    }

  • 相关阅读:
    路由器配置深入浅出—静态路由和缺省路由配置
    盘点飞思卡尔i.MX多媒体处理器前世今生 (转)
    ubuntu18.04下取消中键复制粘贴功能
    uboot常用命令及其使用
    MCU软件最佳实践——使用printf打印数据
    uboot无法通过nfs加载ubuntu18.04中的文件(转)
    GNU C字节对齐__attribute__((aligned(n))) #pragma pack(n)
    ENDIAN的由来及BIGEDIAN 和LITTLEENDIAN(转)
    自动生成c# Model属性
    使用JAVA生成随机的AES密钥
  • 原文地址:https://www.cnblogs.com/KirinSB/p/9409105.html
Copyright © 2020-2023  润新知