Tarjan模板

1.无向图求割点

例题:P3388 【模板】割点(割顶)

#include<queue>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long ll;
const int maxm=200007;
int n,m,ans;
int pre[maxm],last[maxm],other[maxm],l;
bool ge[maxm];
int tot,dfn[maxm],low[maxm];
void add(int x,int y)
{
 l++;
 pre[l]=last[x];
 last[x]=l;
 other[l]=y;	
}
void dfs(int x,int fa)
{
  dfn[x]=low[x]=++tot;
  int child=0;
  for(int p=last[x];p;p=pre[p])
  {
    int v=other[p];
    if(!dfn[v])
    {
      dfs(v,fa);
      low[x]=min(low[x],low[v]);
	  if(dfn[x]<=low[v]&&x!=fa)
	  ge[x]=1;
	  if(x==fa)
	  child++;	
    }
    else low[x]=min(low[x],dfn[v]);
  }
  if(x==fa&&child>=2)
  ge[x]=1;
}
int main()
{
 scanf("%d%d",&n,&m);
 for(int i=1;i<=m;i++)
 {
   int x,y;
   scanf("%d%d",&x,&y);
   add(x,y);
   add(y,x);
 }
 for(int i=1;i<=n;i++)
 {
   if(!dfn[i])
   dfs(i,i);	
 }
 for(int i=1;i<=n;i++)
 if(ge[i]) ans++;
 printf("%d
",ans);
 for(int i=1;i<=n;i++)
 if(ge[i]) printf("%d ",i);
 return 0;	
}

2.有向图求强联通分量

例题:受欢迎的牛

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
int pre[50005],last[10005],other[50005],l;
int dfn[10005],low[10005],stack[10005],c[10005],ins[10005];
int du[10005];
int num;//搜索顺序 
int top,cnt,ans[10005]; 
void add(int x,int y)
{
 l++;
 pre[l]=last[x];
 last[x]=l;
 other[l]=y;	
}
void tarjan(int x)
{
  dfn[x]=low[x]=++num;
  stack[++top]=x;
  ins[x]=1;
  for(int p=last[x];p;p=pre[p])
  {
  	int v=other[p];
  	if(!dfn[v])
  	{
  		tarjan(v);
  		low[x]=min(low[x],low[v]);
  	}
  	else if(ins[v])
  	{
  	  low[x]=min(low[x],dfn[v]);	
  	}
  }
  if(dfn[x]==low[x])
  {
  	cnt++;
  	int y=0;
	while(x!=y){
  	y=stack[top--],ins[y]=0;	
  	c[y]=cnt;
  	ans[cnt]++;
  	}
  }
}
int main()
{
 scanf("%d%d",&n,&m);
 for(int i=1;i<=m;i++)
 {
   int x,y;
   scanf("%d%d",&x,&y);
   add(x,y);	
 }
 for(int i=1;i<=n;i++)
 {
 	if(!dfn[i]) tarjan(i);
 }
 for(int i=1;i<=n;i++)
 {
   for(int p=last[i];p;p=pre[p])
   {
     if(c[i]!=c[other[p]])
     {
     	du[c[i]]++;
     }
   }
 }
 int tt=0;
 for(int i=1;i<=cnt;i++)
 {
   if(!du[i])
   {
   	  if(tt)
   	  {
   	   printf("0
");
		  return 0;	
   	  }
   	  tt=i;
   }
 }
 printf("%d
",ans[tt]);
 return 0;
} 

3.无向图求桥

例题:炸铁路

#include<queue>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long ll;
const int maxm=10507;
int n,m;
int pre[maxm],last[maxm],other[maxm],l;
int tot,dfn[maxm],low[maxm],cnt;
struct node
{
 int x,y;	
}ans[maxm];
bool cmp(node a,node b)
{
 if(a.x==b.x) return a.y<b.y;
 return a.x<b.x;	
}
void add(int x,int y)
{
 l++;
 pre[l]=last[x];	
 last[x]=l;
 other[l]=y;
}
void dfs(int x,int fa)
{
 dfn[x]=low[x]=++tot;
 for(int p=last[x];p;p=pre[p])
 {
  int v=other[p];
  if(v==fa) continue;
  if(!dfn[v])
  {
    dfs(v,x);
	low[x]=min(low[x],low[v]);
	if(dfn[x]<low[v])
    {
       if(x>v) swap(x,v);
       ans[++cnt].x=x;
       ans[cnt].y=v;
    }
  }
  else low[x]=min(low[x],dfn[v]);
 }
}
int main()
{
 scanf("%d%d",&n,&m);
 for(int i=1;i<=m;i++)
 {
  int x,y;
  scanf("%d%d",&x,&y);
  add(x,y);
  add(y,x);
 }
 for(int i=1;i<=n;i++)
 if(!dfn[i]) dfs(i,i);
 sort(ans+1,ans+cnt+1,cmp);
 for(int i=1;i<=cnt;i++)
 {
  	printf("%d %d
",ans[i].x,ans[i].y);
 }
 return 0;	
}

4.缩点

#include<queue>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long ll;
const int maxm=1e5+7;
int n,m,ans;
int w[maxm],val[maxm];
int pre[maxm],last[maxm],other[maxm],l;
int sta[maxm],vis[maxm],tot,dfn[maxm],low[maxm],from[maxm],dis[maxm];
int ru[maxm];
int id[maxm],top;
queue<int> q;
void add(int x,int y)
{
 l++;
 from[l]=x;
 pre[l]=last[x];
 last[x]=l;
 other[l]=y;	
}
void dfs(int x)
{
  dfn[x]=low[x]=++tot;
  sta[++top]=x;
  vis[x]=1;
  for(int p=last[x];p;p=pre[p])
  {
   	int v=other[p];
   	if(!dfn[v])
   	{
   	   dfs(v);
	   low[x]=min(low[x],low[v]);	
   	}
   	else if(vis[v]) low[x]=min(low[x],dfn[v]);
  }
  if(dfn[x]==low[x])
  {
   int y=0;
   while(y!=x)
   {
    y=sta[top--];
    val[x]+=w[y];
    id[y]=x;
    vis[y]=0;
   }
  }
}
void solve()
{
  for(int i=1;i<=n;i++)
  {
    if(id[i]==i&&!ru[i])
    {
	 q.push(i);
	 dis[i]=val[i];
   }
  }
  while(q.size())
  {
   int u=q.front();
   q.pop();
   for(int p=last[u];p;p=pre[p])
   {
   	 int v=other[p];
   	 dis[v]=max(dis[v],dis[u]+val[v]);
   	 ru[v]--;
   	 if(!ru[v]) q.push(v);
   }
  }
  ans=0;
  for(int i=1;i<=n;i++)
  ans=max(ans,dis[i]);
}
int main()
{
 scanf("%d%d",&n,&m);
 for(int i=1;i<=n;i++)
 scanf("%d",w+i);
 for(int i=1;i<=m;i++)
 {
   int x,y;
   scanf("%d%d",&x,&y);
   add(x,y);	
 }
 for(int i=1;i<=n;i++)
 {
  if(!dfn[i])
  dfs(i);	
 }
 memset(last,0,sizeof(last));
 l=0;
 for(int i=1;i<=m;i++)
 {
   int x=id[from[i]],y=id[other[i]];
   if(x!=y)
   {
   	 add(x,y);
   	 ru[y]++;
   }
 }
 solve();
 printf("%d
",ans);
 return 0;	
}
原文地址:https://www.cnblogs.com/lihan123/p/11826338.html