Tarjan各大算法汇总
Posted sun123zxy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tarjan各大算法汇总相关的知识,希望对你有一定的参考价值。
补丁V2.3 增加了割边,割点(前向星)代码
补丁V2.0 计划内容增大,增加了割点(邻接矩阵)代码
补丁V1.1 简化了Tarjan(邻接矩阵)代码
备忘:简化强联通分量(前向星)代码,割边需处理重边,增加其他tarjan算法
强联通分量
邻接矩阵
//邻接矩阵 by sun123zxy
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<queue>
//#include<windows.h>
using namespace std;
int n,m;
int map[1005][1005];
int book[1005];
int instack[1005];
int stack[1005];
int top=0;
int low[1005];
int dfn[1005];
int dfnn=1;
void tarjan(int note) {
instack[note]=1;
book[note]=1;
dfn[note]=dfnn;
dfnn++;
stack[top]=note;
top++;
low[note]=dfn[note];
for(int i=1; i<=n; i++) {
if(map[note][i]==1) {
if(instack[i]==1) {
if(low[note]>dfn[i]) {
low[note]=dfn[i];
}
} else if(book[i]==1) {
} else {
tarjan(i);
if(low[note]>low[i]) {
low[note]=low[i];
}
}
}
}
if(dfn[note]==low[note]) {
for(;;) {
printf("%d",stack[top-1]);//输出分量
instack[stack[top-1]]=0;
top--;
if(stack[top]==note) {
break;
}
}
}
}
int main() {
cin>>n>>m;
for(int i=1;i<=m; i++) {
int t1,t2;
scanf("%d%d",&t1,&t2);
map[t1][t2]=1;
}
for(int i=1;i<=n;i++){
if(book[i]==0){
tarjan(i);
}
}
return 0;
}
前向星
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m;
struct uct1 {
int from,to;
} edge[50005];
int first[50005];
int len[50005];
int dfn[50005];
int low[50005];
int stack[50005];
int top=0;
int instack[50005]= {0};
int book[50005]= {0};
int dfnn=0;
int cmp(uct1 a,uct1 b) {
return a.from<b.from;
}
void tarjan(int now) {
if(first[now]==0){
return;
}
for(int i=first[now];i<first[now]+len[now] ; i++) {
int ito=edge[i].to;
if(instack[ito]==1) {
if(low[now]>dfn[ito]) {
low[now]=dfn[ito];
}
continue;
} else if(book[ito]==1) {
continue;
} else {
book[ito]=1;
instack[ito]=1;
stack[top]=ito;
top++;
dfnn++;
dfn[ito]=dfnn;
low[ito]=dfn[ito];
tarjan(ito);
if(low[now]>low[ito]) {
low[now]=low[ito];
}
if(low[ito]==dfn[ito]) {
for(;;) {
printf("%d ",stack[top-1]);
instack[stack[top-1]]=0;
top--;
if(stack[top]==ito) {
break;
}
}
cout<<endl;
}
}
}
}
int main() {
cin>>n>>m;
for(int i=1; i<=m; i++) {
int t1,t2;
scanf("%d%d",&t1,&t2);
edge[i].from=t1;
edge[i].to=t2;
}
sort(edge+1,edge+m+1,cmp);
first[edge[1].from]=1;
len[edge[1].from]=1;
for(int i=2; i<=m; i++) {
if(edge[i].from!=edge[i-1].from) {
first[edge[i].from]=i;
}
len[edge[i].from]++;
}
for(int i=1; i<=n; i++) {
if(book[i]==0) {
book[i]=1;
instack[i]=1;
stack[top]=i;
top++;
dfnn++;
dfn[i]=dfnn;
low[i]=dfn[i];
tarjan(i);
if(low[i]==dfn[i]) {
for(;;) {
if(top==0) {
break;
}
printf("%d ",stack[top-1]);
instack[stack[top-1]]=0;
top--;
}
cout<<endl;
}
for(int i=0; i<2005; i++) {
instack[i]=0;
}
dfnn=0;
}
}
return 0;
}
割点
邻接矩阵
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<queue>
//#include<windows.h>
using namespace std;
int n,m;
int map[105][105];
int book[105];
int instack[105];
int stack[105];
int top=0;
int low[105];
int dfn[105];
int dfnn=1;
int ans[105];
int ansn=0;
void tarjan(int note,int fa) {
int chin=0;//记录该点孩子个数,判定根节点是否为割点时用
instack[note]=1;
book[note]=1;
dfn[note]=dfnn;
dfnn++;
stack[top]=note;
top++;
low[note]=dfn[note];
for(int i=1; i<=n; i++) {
if(map[note][i]==1&&i!=fa) {
chin++;
if(instack[i]==1) {
if(low[note]>dfn[i]) {
low[note]=dfn[i];
}
} else if(book[i]==1) {
} else {
tarjan(i,note);
if(low[note]>low[i]) {
low[note]=low[i];
}
if(fa==-1) {//若为根节点
if(chin>=2){//若孩子数大于等于2,是割点
ans[ansn]=note;
ansn++;
}
} else {
if(dfn[note]<=low[i]) {
ans[ansn]=note;
ansn++;
}
}
}
}
}
if(dfn[note]==low[note]) {
for(;;) {
instack[stack[top-1]]=0;
top--;
if(stack[top]==note) {
break;
}
}
}
}
int main() {
cin>>n>>m;
for(int i=1; i<=m; i++) {
int t1,t2;
scanf("%d%d",&t1,&t2);
map[t1][t2]=1;
map[t2][t1]=1;
}
tarjan(1,-1);
cout<<ansn<<endl;
for(int i=0; i<ansn; i++) {//需进一步去重,因为如有一点可能成为多个割点。e.g:1-2,2-3,2-4
cout<<ans[i]<<‘ ‘;
}
return 0;
}
前向星
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<queue>
using namespace std;
struct uct1 {
int from,to;
} edge[100005];
int first[100005];
int size[100005];
int n,m;
int book[100005];
int instack[100005];
int stack[100005];
int top=0;
int low[100005];
int dfn[100005];
int dfnn=1;
int ans[100005];
int ansn=0;
void tarjan(int note,int fa) {
int chin=0;//记录该点孩子个数,判定根节点是否为割点时用
instack[note]=1;
book[note]=1;
dfn[note]=dfnn;
dfnn++;
stack[top]=note;
top++;
low[note]=dfn[note];
for(int ti=first[note]; ti<=first[note]+size[note]-1; ti++) {
int i=edge[ti].to;
if(i!=fa) {
chin++;
if(instack[i]==1) {
if(low[note]>dfn[i]) {
low[note]=dfn[i];
}
} else if(book[i]==1) {
} else {
tarjan(i,note);
if(low[note]>low[i]) {
low[note]=low[i];
}
if(fa==-1) {//若为根节点
if(chin>=2) { //若孩子数大于等于2,是割点
ans[ansn]=note;
ansn++;
}
} else {
if(dfn[note]<=low[i]) {
ans[ansn]=note;
ansn++;
}
}
}
}
}
if(dfn[note]==low[note]) {
for(;;) {
instack[stack[top-1]]=0;
top--;
if(stack[top]==note) {
break;
}
}
}
}
bool cmp(uct1 x,uct1 y) {
if(x.from<y.from) {
return 1;
} else if(x.from>y.from) {
return 0;
} else {
return x.to<y.to;
}
}
int main() {
cin>>n>>m;
m=m*2;
for(int i=1; i<=m; i+=2) {
int t1,t2;
scanf("%d%d",&t1,&t2);
edge[i].from=t1;
edge[i].to=t2;
edge[i+1].from=t2;
edge[i+1].to=t1;
}
sort(edge+1,edge+1+m,cmp);
for(int i=1; i<=m; i++) {
if(edge[i].from!=edge[i-1].from) {
first[edge[i].from]=i;
}
size[edge[i].from]++;
}
tarjan(1,-1);
cout<<ansn<<endl;
for(int i=0; i<ansn; i++) {//需进一步去重,因为有点可能多次被判定为割点。e.g:1-2,2-3,2-4
cout<<ans[i]<<‘ ‘;
}
return 0;
}
割边
邻接矩阵(未处理重边)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<queue>
//#include<windows.h>
using namespace std;
int n,m;
int map[5005][5005];
int book[5005];
int instack[5005];
int stack[5005];
int top=0;
int low[5005];
int dfn[5005];
int dfnn=1;
int ans=0;
void tarjan(int note,int fa) {
instack[note]=1;
book[note]=1;
dfn[note]=dfnn;
dfnn++;
stack[top]=note;
top++;
low[note]=dfn[note];
for(int i=1; i<=n; i++) {
if(map[note][i]==1&&i!=fa) {
if(instack[i]==1) {
if(low[note]>dfn[i]) {
low[note]=dfn[i];
}
} else if(book[i]==1) {
} else {
tarjan(i,note);
if(low[note]>low[i]) {
low[note]=low[i];
}
if(dfn[note]<low[i]) {
ans++;
}
}
}
}
if(dfn[note]==low[note]) {
for(;;) {
instack[stack[top-1]]=0;
top--;
if(stack[top]==note) {
break;
}
}
}
}
int main() {
cin>>n>>m;
for(int i=1; i<=m; i++) {
int t1,t2;
scanf("%d%d",&t1,&t2);
map[t1][t2]=1;
map[t2][t1]=1;
}
tarjan(1,-1);
cout<<ans<<endl;
return 0;
}
前向星(未处理重边)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<queue>
using namespace std;
struct uct1{
int from,to;
}edge[100005];
int first[100005];
int size[100005];
int n,m;
int book[100005];
int instack[100005];
int stack[100005];
int top=0;
int low[100005];
int dfn[100005];
int dfnn=1;
int ans=0;
void tarjan(int note,int fa) {
instack[note]=1;
book[note]=1;
dfn[note]=dfnn;
dfnn++;
stack[top]=note;
top++;
low[note]=dfn[note];
for(int ti=first[note]; ti<=first[note]+size[note]-1; ti++) {
int i=edge[ti].to;
if(i!=fa) {
if(instack[i]==1) {
if(low[note]>dfn[i]) {
low[note]=dfn[i];
}
} else if(book[i]==1) {
} else {
tarjan(i,note);
if(low[note]>low[i]) {
low[note]=low[i];
}
if(dfn[note]<low[i]) {
ans++;
}
}
}
}
if(dfn[note]==low[note]) {
for(;;) {
instack[stack[top-1]]=0;
top--;
if(stack[top]==note) {
break;
}
}
}
}
bool cmp(uct1 x,uct1 y){
if(x.from<y.from){
return 1;
}else if(x.from>y.from){
return 0;
}else{
return x.to<y.to;
}
}
int main() {
cin>>n>>m;
m=m*2;
for(int i=1; i<=m; i+=2) {
int t1,t2;
scanf("%d%d",&t1,&t2);
edge[i].from=t1;
edge[i].to=t2;
edge[i+1].from=t2;
edge[i+1].to=t1;
}
sort(edge+1,edge+1+m,cmp);
for(int i=1;i<=m;i++){
if(edge[i].from!=edge[i-1].from){
first[edge[i].from]=i;
}
size[edge[i].from]++;
}
tarjan(1,-1);
cout<<ans<<endl;
return 0;
}
以上是关于Tarjan各大算法汇总的主要内容,如果未能解决你的问题,请参考以下文章
各大互联网Java面试题汇总,最后我成功拿到百度的offer