找环
圆方树: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.造一张仙人掌图
比较暴力的做法就随机的树(高度比较低)
然后随机两个点,看这之间的点是不是都没被覆盖