标签:tar printf 更新 sizeof php ble can space 连通性
tajan的dfs树系列算法:
求解割点,桥,强连通分量,点双联通分量,边双联通分量;
tajan是一个dfs,把一个图变成一个dfs树结构,
dfs树结构,本质是通过一个没有任何要求的dfs把图的边分为:树边和返祖边:
在有向图中,除了这二种边外,还有父节点与曾遍历过的子节点间的边,然而这个子节点不是父节点的祖先,
然而这种边在tarjan中没有意义,我们所求的东西用不上她们
伪代码:
深搜(点now){
更新点now——
dfs序(dfn)与目前可到dfn最小祖先的dfn(low),标记已经遍历(vis),确认now将是他后继递归的点的祖先(instk),其他
for(以now为起点的所有边)
if(边终点to未遍历)
深搜(to),low[now]=min(low[now],low[to])
else
if(instk[to]为真)//无向图可以不存在这个
low[now]=min(low[now],dfn[to])
更新instk[now]为假
}
求(无向图)割点,桥:
割点:无向图中,删除之可改变图的连通性的点
两种:
桥:无向图中,删除之可改变图的连通性的边
一种:
两个边双连通分量间的连边;
求法:
割点:这个点儿子中有至少一个的low小于这个点的dfn
桥:该边终点的low=dfn
例题:
code:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,m; struct ss{ int to,next; }e[200010]; struct Cl{ int u,v; }Cedge[200010]; int first[20010],num; int pnu,enu; int Cpoint[20010]; int dfn[20010],low[20010],vis[20010]; bool cmp(Cl a,Cl b){ return a.u<b.u||(a.u==b.u&&a.v<b.v); } void Input(); void work(); void Output(); void build(int ,int ); void Init(); void dfs_1(int ,int ); void dfs_2(int ,int ); int main() { Input(); work(); Output(); return 0; } void Input(){ int i,j,k; scanf("%d%d",&n,&m); for(i=1;i<=m;i++){ scanf("%d%d",&j,&k); build(j,k);build(k,j); } } void work(){ pnu=0;enu=0; Init(); dfs_1(1,0); Init(); dfs_2(1,0); } void Output(){ int i; for(i=1;i<=enu;i++) if(Cedge[i].u>Cedge[i].v) swap(Cedge[i].u,Cedge[i].v); sort(Cpoint+1,Cpoint+pnu+1); sort(Cedge+1,Cedge+enu+1,cmp); for(i=1;i<=pnu;i++) printf("%d ",Cpoint[i]); if(pnu==0) printf("Null"); printf("\n"); for(i=1;i<=enu;i++) printf("%d %d\n",Cedge[i].u,Cedge[i].v); } void build(int f,int t){ e[++num].next=first[f]; e[num].to=t; first[f]=num; } void Init(){ memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(vis,0,sizeof(vis)); num=0; } void dfs_1(int now,int fa){ int i,p=0; if(now!=1)p=1; dfn[now]=low[now]=++num;vis[now]=1; for(i=first[now];i;i=e[i].next) if(e[i].to!=fa){ if(!vis[e[i].to]){ dfs_1(e[i].to,now); if(low[e[i].to]>=dfn[now])p++; if(low[now]>low[e[i].to]) low[now]=low[e[i].to]; } else if(low[now]>dfn[e[i].to]) low[now]=dfn[e[i].to]; } if(p>=2) Cpoint[++pnu]=now; } void dfs_2(int now,int fa){ int i; dfn[now]=low[now]=++num;vis[now]=1; for(i=first[now];i;i=e[i].next) if(e[i].to!=fa){ if(!vis[e[i].to]){ dfs_2(e[i].to,now); if(low[now]>low[e[i].to]) low[now]=low[e[i].to]; if(low[e[i].to]>dfn[now]) Cedge[++enu].u=now,Cedge[enu].v=e[i].to; } else if(low[now]>dfn[e[i].to]) low[now]=dfn[e[i].to]; } }
求(有向图)强连通分量:
强联通分量:有向图中,点的可以相互到达的关系可以传递,于是有这个关系的一组点与其间的边构成一个强连通分量
求法:
每遍历一个点时,使之进栈,
当遍历结束时,
若其low=dfn,则从栈顶到该节点的所有点属于同一分量,且该分量不含其它点,标记她们,并使她们出栈
(now永远不能到达上层的点,于是她与她的子树中没有自成一派的点构成强连通分量,自成一派的点已经出栈了)
例题:
强连通分量缩点后讨论无出度点的个数
code:
#include<cstdio> using namespace std; struct ss{ int to,next; }e[2000010]; int first[200010],num; int dfn[100010],low[100010],vis[200010],stk[100010],col[100010],number; int numcol[200010],into[100],color; int max[200010]; long long f[200010],x; int n,m; void Input(); void work(); void Output(); void build(int ,int ); void tar(int ); void con_poi(); void dfs(int ); int main() { Input(); work(); Output(); return 0; } void Input(){ int i,j,k; scanf("%d%d%lld",&n,&m,&x); for(i=1;i<=m;i++){ scanf("%d%d",&j,&k); build(j,k); } } void work(){ int i,j; color=n; for(i=1;i<=n;i++) if(!vis[i]) number=0,tar(i); con_poi(); for(i=n+1;i<=color;i++) if(!vis[i]) dfs(i); } void Output(){ int i; long long ans=0,ans_=0; for(i=n+1;i<=color;i++){ if(max[i]==ans) (ans_+=f[i])%=x; if(max[i]>ans) ans=max[i],ans_=f[i]; } printf("%lld\n%lld\n",ans,ans_); } void build(int f,int t){ e[++num].next=first[f]; e[num].to=t; first[f]=num; } void tar(int now){ int i; dfn[now]=low[now]=++number; vis[now]=2;stk[++stk[0]]=now; for(i=first[now];i;i=e[i].next) if(!vis[e[i].to]){ tar(e[i].to); if(low[now]>low[e[i].to]) low[now]=low[e[i].to]; } else if(vis[e[i].to]==2&&low[now]>dfn[e[i].to]) low[now]=dfn[e[i].to]; if(dfn[now]==low[now]){ ++color; while(stk[stk[0]+1]!=now){ col[stk[stk[0]]]=color; vis[stk[stk[0]]]=1; ++numcol[color]; --stk[0]; } number=stk[0]; } } void con_poi(){ int i,j; for(i=1;i<=n;i++) for(j=first[i];j;j=e[j].next) if(col[i]!=col[e[j].to]) build(col[i],col[e[j].to]),into[col[e[j].to]]++; } void dfs(int now){ int i; f[now]=1;max[now]=numcol[now]; for(i=first[now];i;i=e[i].next) if(!vis[e[i].to]){ vis[e[i].to]=1; if(!f[e[i].to]) dfs(e[i].to); if(max[now]==max[e[i].to]+numcol[now]) (f[now]+=f[e[i].to])%=x; if(max[now]<max[e[i].to]+numcol[now]){ max[now]=max[e[i].to]+numcol[now]; f[now]=f[e[i].to]; } } for(i=first[now];i;i=e[i].next) if(vis[e[i].to]) vis[e[i].to]=0; }
强连通分量缩点,计算最长路和最长路计数
code:
#include<cstdio> using namespace std; struct ss{ int to,next; }e[2000010]; int first[200010],num; int dfn[100010],low[100010],vis[200010],stk[100010],col[100010],number; int numcol[200010],into[100],color; int max[200010]; long long f[200010],x; int n,m; void Input(); void work(); void Output(); void build(int ,int ); void tar(int ); void con_poi(); void dfs(int ); int main() { Input(); work(); Output(); return 0; } void Input(){ int i,j,k; scanf("%d%d%lld",&n,&m,&x); for(i=1;i<=m;i++){ scanf("%d%d",&j,&k); build(j,k); } } void work(){ int i,j; color=n; for(i=1;i<=n;i++) if(!vis[i]) number=0,tar(i); con_poi(); for(i=n+1;i<=color;i++) if(!vis[i]) dfs(i); } void Output(){ int i; long long ans=0,ans_=0; for(i=n+1;i<=color;i++){ if(max[i]==ans) ans_+=f[i]; if(max[i]>ans) ans=max[i],ans_=f[i]; } printf("%lld\n%lld\n",ans,ans_); } void build(int f,int t){ e[++num].next=first[f]; e[num].to=t; first[f]=num; } void tar(int now){ int i; dfn[now]=low[now]=++number; vis[now]=2;stk[++stk[0]]=now; for(i=first[now];i;i=e[i].next) if(!vis[e[i].to]){ tar(e[i].to); if(low[now]>low[e[i].to]) low[now]=low[e[i].to]; } else if(vis[e[i].to]==2&&low[now]>dfn[e[i].to]) low[now]=dfn[e[i].to]; if(dfn[now]==low[now]){ ++color; while(stk[stk[0]+1]!=now){ col[stk[stk[0]]]=color; vis[stk[stk[0]]]=1; ++numcol[color]; --stk[0]; } number=stk[0]; } } void con_poi(){ int i,j; for(i=1;i<=n;i++) for(j=first[i];j;j=e[j].next) if(col[i]!=col[e[j].to]) build(col[i],col[e[j].to]),into[col[e[j].to]]++; } void dfs(int now){ int i; f[now]=1;max[now]=numcol[now]; for(i=first[now];i;i=e[i].next) if(!vis[e[i].to]){ vis[e[i].to]=1; if(!f[e[i].to]) dfs(e[i].to); if(max[now]==max[e[i].to]+numcol[now]) (f[now]+=f[e[i].to])%=x; if(max[now]<max[e[i].to]+numcol[now]){ max[now]=max[e[i].to]+numcol[now]; f[now]=f[e[i].to]; } } for(i=first[now];i;i=e[i].next) if(vis[e[i].to]) vis[e[i].to]=0; }
强连通分量缩点,乱搞,具体看代码;
code:
#include<cstdio> #include<cstring> using namespace std; int n,m,p,ans; struct ss{ int to,next; }e[600010]; int first[200010],num; int dfn[100010],low[100010],vis[200010],stk[200010],number; int col[100010],color,numcol[200010]; int toit[200010]; void Input(); void work(); void Output(); void build(int ,int ); void tar(int ); void dfs_1(int ); int main() { Input(); work(); Output(); return 0; } void Input(){ int i,j,k; scanf("%d%d",&n,&m); for(i=1;i<=m;i++){ scanf("%d%d",&j,&k); build(j,k); } } void work(){ int i,j,k; color=n; for(i=1;i<=n;i++) if(!vis[i]) number=0,tar(i); for(i=1;i<=n;i++) for(j=first[i];j;j=e[j].next) if(col[i]!=col[e[j].to]) build(col[i],col[e[j].to]),toit[col[e[j].to]]++; memset(stk,0,sizeof(stk)); for(i=n+1;i<=color;i++) if(!toit[i]) vis[i]++,dfs_1(i); for(i=n+1;i<=color;i++) if(!toit[i]){ k=(numcol[i]==1); for(j=first[i];j;j=e[j].next) k&=(vis[e[j].to]>1); p|=k; ans++; } } void Output(){ printf("%.6lf",1.0-(double)(ans-p)/(double)(n)); } void build(int f,int t){ e[++num].next=first[f]; e[num].to=t; first[f]=num; } void tar(int now){ int i; dfn[now]=low[now]=++number; stk[++stk[0]]=now;vis[now]=2; for(i=first[now];i;i=e[i].next) if(!vis[e[i].to]){ tar(e[i].to); if(low[now]>low[e[i].to]) low[now]=low[e[i].to]; } else if(vis[e[i].to]==2&&low[now]>dfn[e[i].to]) low[now]=dfn[e[i].to]; if(dfn[now]==low[now]){ ++color; while(stk[stk[0]+1]!=now){ col[stk[stk[0]]]=color; vis[stk[stk[0]]]=1; ++numcol[color]; --stk[0]; } number=stk[0]; } } void dfs_1(int now){ int i; for(i=first[now];i;i=e[i].next) if(!stk[e[i].to]){ stk[e[i].to]=1; vis[e[i].to]++; if(vis[e[i].to]==1) dfs_1(e[i].to); } for(i=first[now];i;i=e[i].next) if(stk[e[i].to]) stk[e[i].to]=0; }
边双点双下次再说吧;
标签:tar printf 更新 sizeof php ble can space 连通性
原文地址:http://www.cnblogs.com/nietzsche-oier/p/7522401.html