Tarjan各大算法匯總
阿新 • • 發佈:2018-07-09
未處理 cstring else break 等於 window str clu 一點
補丁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各大算法匯總