• #Tarjan,拓扑排序#洛谷 3436 [POI2006]PRO-Professor Szu


    题目


    分析

    考虑有向图缩点然后拓扑排序,
    最恶心的地方是这题有自环,
    一旦存在自环就意味着答案一定超过阈值
    其实更难过的是Tarjan大小写写错没有发现qwq


    代码

    #include <cstdio>
    #include <cctype>
    #include <stack>
    #include <queue>
    #define rr register
    using namespace std;
    const int N=1000011;
    stack<int>stac; queue<int>q;
    struct node{int y,next;}e[N],E[N];
    int dfn[N],low[N],v[N],col[N],siz[N],m,ans,Ans;
    int deg[N],n,et,Et,cnt,tot,as[N],hs[N],dp[N];
    inline signed iut(){
    	rr int ans=0; rr char c=getchar();
    	while (!isdigit(c)) c=getchar();
    	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    	return ans;
    }
    inline signed min(int a,int b){return a<b?a:b;}
    inline void tarjan(int x){
    	dfn[x]=low[x]=++tot,
    	v[x]=1,stac.push(x);
    	for (rr int i=hs[x];i;i=E[i].next)
    	if (!dfn[E[i].y]){
    		tarjan(E[i].y);
    		low[x]=min(low[x],low[E[i].y]); 
    	}else if (v[E[i].y])
    	    low[x]=min(low[x],dfn[E[i].y]);
    	if (dfn[x]==low[x]){
    		rr int y; ++cnt;
    		do{
    			y=stac.top(); stac.pop();
    			col[y]=cnt,++siz[cnt],v[y]=0;
    		}while (x^y);
    	}
    }
    signed main(){
    	n=iut()+1,m=iut();
    	for (rr int i=1;i<=m;++i){
    		rr int y=iut(),x=iut();
    		E[++Et]=(node){y,hs[x]},hs[x]=Et;
    	}
    	for (rr int i=1;i<=n;++i)
    	    if (!dfn[i]) tarjan(i);
    	for (rr int i=1;i<=n;++i)
    	for (rr int j=hs[i];j;j=E[j].next)
    	if (i==E[j].y) ++siz[col[i]];
    	else if (col[i]^col[E[j].y]){
    		e[++et]=(node){col[E[j].y],as[col[i]]},
    		as[col[i]]=et,++deg[col[E[j].y]];
    	}
    	for (rr int i=1;i<=cnt;++i)
    	    if (!deg[i]) q.push(i);
    	dp[col[n]]=1,v[col[n]]=1;
    	while (!q.empty()){
    		rr int x=q.front(); q.pop();
    		for (rr int i=as[x];i;i=e[i].next){
    			if (!(--deg[e[i].y])) q.push(e[i].y);
    			if (v[x]) v[e[i].y]=1; dp[e[i].y]+=dp[x];
    			if (siz[e[i].y]>1&&v[e[i].y]) dp[e[i].y]=36501;
    			if (dp[e[i].y]>36501) dp[e[i].y]=36501;
    		}
    	}
    	for (rr int i=1;i<=cnt;++i)
    	    if (v[i]&&ans<dp[i]) ans=dp[i];
    	if (ans==36501) printf("zawsze
    ");
    	    else printf("%d
    ",ans);
    	for (rr int i=1;i<=n;++i)
    	    if (v[col[i]]&&ans==dp[col[i]]) ++Ans;
    	printf("%d
    ",Ans);
    	for (rr int i=1;i<=n;++i)
    	    if (v[col[i]]&&ans==dp[col[i]])
    		    printf("%d ",i);
    	return 0;
    } 
    
  • 相关阅读:
    写代码随想
    学生管理系统
    自定义栈
    位运算符加密
    自定义Vector
    二叉树排序
    双向循环链表
    双向链表
    加载properties文件
    通讯录
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/13928646.html
走看看 - 开发者的网上家园