tarjan进阶
Posted yu-shi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了tarjan进阶相关的知识,希望对你有一定的参考价值。
模板向。
以前学的scc已经差不多可以倒着打了。求scc和缩点还是比较好搞的(当然,必经点和边确实没学)。
现在学一学求eDcc和vDcc的tarjan。
求eDcc,只要学会求桥,然后dfs染色即可,至于缩点就是枚举每条边然后新建图。
桥的判定要low[y]>dfn[x],因为只有这样才不能回到dfs树在x以上的位置。而且由于一些重边问题,tarjan开第二参量,确定low值不被自己更新,需要用到邻接表成对变换。
#include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<cstdio> #include<vector> #include<queue> #include<stack> #include<set> #include<map> using namespace std; int read() int sum=0,f=1;char x=getchar(); while(x<‘0‘||x>‘9‘) if(x==‘-‘) f=-1; x=getchar(); while(x>=‘0‘&&x<=‘9‘) sum=sum*10+x-‘0‘; x=getchar(); return sum*f; struct EDGE int ed,nex; edge[100],edgec[100]; int first[50],firstc[50],num=1,numc; int n,m; int dfn[50],low[50],bl[50]; int ord,ecc; bool bridge[100]; void add(int st,int ed) edge[++num].ed=ed; edge[num].nex=first[st]; first[st]=first[st]; void addc(int st,int ed) edgec[++numc].ed=ed; edgec[numc].nex=firstc[st]; firstc[st]=numc; void tarjan(int x,int in_edge) dfn[x]=low[x]=++ord; for(int i=first[x];i;i=edge[i].nex) int y=edge[i].ed; if(!dfn[y]) tarjan(y); low[x]=min(low[x],low[y]); if(low[y]>dfn[x]) bridge[i]=bridge[i^1]=1; else if(i!=(in_edge^1)) low[x]=min(low[x],dfn[y]); void dfs(int x) bl[x]=ecc; for(int i=first[x];i;i=edge[i].nex) int y=edge[i].ed; if(bl[y]||bridge[i]) continue; dfs(y); int main() n=read();m=read(); for(int i=1,x,y;i<=m;i++) x=read();y=read(); add(x,y);add(y,x); for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,0);//求桥 for(int i=1;i<=n;i++) if(!bl[i]) ecc++; dfs(i); for(int i=2;i<=num;i++) int x=edge[i].ed,y=edge[i^1].ed; if(bl[x]==bl[y]) continue; addc(bl[x],bl[y]);
求vDcc,要学会求割点,在求割点的程序里套上一个用vector存vDcc的子块即可。
割点的判定要low[y]>=dfn[x],而且因为搜索树的性质,需要单独判断根的情况。
缩点的时候因为一个割点可以在两个vDcc里,所以先将割点单独编号,然后建新边。
#include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<cstdio> #include<vector> #include<queue> #include<stack> #include<set> #include<map> using namespace std; struct EDGE int ed,nex; edge[200],edgec[200]; int first[100],firstc[100]; int n,m,ord,top,root,vccnum,nvcn; int dfn[100],low[100],sta[101000],new_id[100],bl[100]; vector<int>vcc[100]; bool cut[100]; int read() int sum=0,f=1;char x=getchar(); while(x<‘0‘||x>‘9‘) if(x==‘-‘) f=-1; x=getchar(); while(x>=‘0‘&&x<=‘9‘) sum=sum*10+x-‘0‘; x=getchar(); return sum*f; void add(int st,int ed) edge[++num].ed=ed; edge[num].nex=first[st]; first[st]=num; void addc(int st,int ed) edgec[++numc].ed=ed; edgec[numc].nex=firstc[st]; firstc[st]=numc; void tarjan(int x) dfn[x]=low[x]=++ord; sta[++top]=x; if(root==x&&first[x]==0) vcc[++vccnum].push_back(x); return ; int child=0; for(int i=first[x];i;i=edge[i].nex) int y=edge[i].ed; if(!dfn) tarjan(y); low[x]=min(low[x],low[y]); if(low[y]>=dfn[x]) child++; if((x==root&&child>=2)||(x!=root&&child>0)) cut[x]=1; vcc[++vccnum].push_back(x); int p; do p=sta[top--]; vcc[vccnum].push_back(p); while(p!=y); else low[x]=min(low[x],dfn[y]); int main() n=read();m=read(); for(int i=1,x,y;i<=m;i++) x=read();y=read(); add(x,y);add(y,x); for(int i=1;i<=n;i++) if(!dfn[i]) root,tarjan(i); nvcn=vccnum; for(int i=1;i<=n;i++) if(cut[i]) new_id[i]=++nvcn; for(int i=1;i<=vccnum;i++) for(int j=0;j<vcc[i].size();j++) int x=vcc[i][j]; if(cut[x]) addc(new_id[x],i); addc(i,new_id[x]); else bl[x]=i;
以上代码均未测试,如有错误自行改正。
以上是关于tarjan进阶的主要内容,如果未能解决你的问题,请参考以下文章