Tarjan模板

青春壹個敷衍的年華 提交于 2019-12-04 01:04:06

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\n",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\n");
          return 0; 
      }
      tt=i;
   }
 }
 printf("%d\n",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\n",ans[i].x,ans[i].y);
 }
 return 0;  
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!