找环

圆方树:https://www.cnblogs.com/cjyyb/p/9098400.html

1.点双连通分量

找到了一个新的不错的模板

void dfs(int x,int y)
{
    dfn[x]=low[x]=++cnt;
    int ch=0;
    for (rint u=head[x];u;u=e[u].a)
    {
        int v=e[u].b;
        if (v==y) continue;
        if (!dfn[v])
        {
            st[++top2]=v;
            dfs(v,x);
            if (low[v]>=dfn[x])
            {
                iscut[x]=1;
                bcc[++cnt3].clear();
                do{
                    bcc[cnt3].push_back(st[top2]);
                }while (st[top2--]!=v);
                bcc[cnt3].push_back(x);
            }
            if (low[v]<low[x]) low[x]=low[v];
        }
        if (dfn[v]<low[x]) low[x]=dfn[v];
    }
    if (x==1&&ch<=1) iscut[1]=0;
}

缩点双的缩法是 把除割点以外的点双缩一起,割点单独

因为两点之间可能有多条边 所以要用并查集维护

2.边双连通分量

缩完之后两个块之间一定只有一条边(不然就是1个边双了)

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <stack>
#include <cmath>
#include <cstring>
using namespace std;
#define rint register int
#define IL inline
#define rep(i,h,t) for (int i=h;i<=t;i++)
#define dep(i,t,h) for (int i=t;i>=h;i--)
#define me(x) memset(x,0,sizeof(x))
const int N=1e5;
int n,m,head[N],l,cnt,scc_cnt,scc[N],f[N],dfn[N],low[N];
bool vis[N];
struct re{
  int a,b;
}e[N*2],jl[N];
stack<int> S;
void arr(int x,int y)
{
  e[++l].a=head[x];
  e[l].b=y;
  head[x]=l;
}
void dfs(int x,int y)
{
  S.push(x);
  dfn[x]=low[x]=++cnt;
  for (rint u=head[x];u;u=e[u].a)
  {
    rint v=e[u].b;
    if (v!=y)
    {
      if (!dfn[v])
      {
        dfs(v,x);
        low[x]=min(low[x],low[v]);
      }
      low[x]=min(low[x],dfn[v]);
    }
  }
  if (low[x]==dfn[x])
  {
    scc_cnt++;
    while (1)
    {
      int v=S.top(); S.pop();
      scc[v]=scc_cnt;
      if (v==x) break;
    }
  }
}
int main()
{
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
  ios::sync_with_stdio(false);
  while (cin>>n>>m)
  {
    l=0; me(head); me(f); cnt=0; scc_cnt=0;
    int x,y;
    rep(i,1,m)
    {
      cin>>x>>y;
      arr(x,y); arr(y,x);
      jl[i].a=x; jl[i].b=y;
    }
    rep(i,1,n) if (!vis[i]) dfs(i,0);
    rep(i,1,m) 
      if (scc[jl[i].a]!=scc[jl[i].b])
        f[scc[jl[i].a]]++,f[scc[jl[i].b]]++;
    int ans=0;
    rep(i,1,n) if (f[i]==1) ans++;
    cout<<(ans+1)/2<<endl;
  }
  return 0;
}

3.强连通分量

4.仙人掌图找环

void find(ll x,ll y)
{
    do
    {
        st1[++top]=x;
        st2[top]=faqz[x];
        belong[x]=1;
        if (x==y) break;
        x=fa[x];
    }while (1);
}
void dfs(ll x,ll y)
{
    dfn[x]=low[x]=++cnt; fa[x]=y;
    for (rint u=head[x];u;u=e[u].a)
    {
        rint v=e[u].b;
        if (v==y) continue;
        faqz[v]=e[u].c;
        if (!dfn[v]) dfs(v,x);
        if (dfn[v]<dfn[x])
        {
            find(x,v);
        }
    }
}

这么写就可以啦 很简单

5.判断一张图是不是仙人掌

无向图:poj 2793

有向图:hdu 3594

6.造一张仙人掌图

比较暴力的做法就随机的树(高度比较低)

然后随机两个点,看这之间的点是不是都没被覆盖

原文地址:https://www.cnblogs.com/yinwuxiao/p/9813811.html