tarjan求割点 poj 1144
2011-05-12 22:26
344 查看
tarjan可真是多才多艺,既求强连通,又求割点割边,还求lca,居然每一种都相差不多。
求割点主要是利用dfs遍历树(李顶龙童鞋一直不理解tarjan,从dfs树理解应该比较直观)。
rel[x]记录x实际在树中深度,low[x]记录x及其子树在树中回边可到达的最浅深度。
如果u是割点,那么在dfs树中
1、u为根,u有一个以上子树(删除u后显然两子树不连通)。
2、u非叶子(易知叶子无关紧要),且low[u的孩子]>=rel[u](即该子树无法不通过u到达u的祖先)
下面是代码(跑不到0ms)
附缩点双联通分量
每次点入栈,把回边和父亲边加进去
hdu3686
拆边为点,考虑地更少
求割点主要是利用dfs遍历树(李顶龙童鞋一直不理解tarjan,从dfs树理解应该比较直观)。
rel[x]记录x实际在树中深度,low[x]记录x及其子树在树中回边可到达的最浅深度。
如果u是割点,那么在dfs树中
1、u为根,u有一个以上子树(删除u后显然两子树不连通)。
2、u非叶子(易知叶子无关紧要),且low[u的孩子]>=rel[u](即该子树无法不通过u到达u的祖先)
下面是代码(跑不到0ms)
var time,ans,son,n:longint; rel,low:array[1..100]of longint; b:array[1..100,0..100]of longint; procedure dfs(x:longint); var i,ne:longint; flag:boolean; begin flag:=false; inc(time);rel[x]:=time;low[x]:=rel[x]; for i:=1 to b[x,0] do begin ne:=b[x,i]; if rel[ne]<>0 then begin if rel[ne]<low[x] then low[x]:=rel[ne] end else begin dfs(ne); if low[ne]<low[x] then low[x]:=low[ne]; if low[ne]>=rel[x] then flag:=true end end; if flag then inc(ans) end; procedure init; var i,j,ne,x,y:longint; begin readln(n); if n=0 then exit; fillchar(b,sizeof(b),0); while not(seekeof) do begin read(x); if x=0 then break; while not (seekeoln) do begin read(y); inc(b[x,0]);b[x,b[x,0]]:=y; inc(b[y,0]);b[y,b[y,0]]:=x end; readln end; readln; fillchar(rel,sizeof(rel),0); fillchar(low,sizeof(low),0); son:=0;ans:=0; rel[1]:=1;low[1]:=1; for i:=1 to b[1,0] do begin ne:=b[1,i];time:=1; if rel[ne]=0 then begin inc(son);dfs(ne) end end; if son>1 then inc(ans); writeln(ans) end; begin assign(input,'1144.in');reset(input); while not(seekeof) do init; close(input) end.
附缩点双联通分量
每次点入栈,把回边和父亲边加进去
hdu3686
#include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> using namespace std; int tail[200000],next[2000000],sora[2000000],id[2000000],po[2000000]; int st[200000],f[50000][18],g[50000][18],rel[200000],low[200000],d[200000],flag[200000]; int top,n,m,ss,w_time,block,b[200000]; void link(int x,int y,int i) { ++ss,next[tail[x]]=ss,tail[x]=ss,sora[ss]=y,next[ss]=0,id[ss]=i; ++ss,next[tail[y]]=ss,tail[y]=ss,sora[ss]=x,next[ss]=0,id[ss]=i; po[ss]=ss-1,po[ss-1]=ss; } void link2(int x,int y) { // cout<<x<<' '<<y<<endl; ++ss,next[tail[x]]=ss,tail[x]=ss,sora[ss]=y,next[ss]=0; ++ss,next[tail[y]]=ss,tail[y]=ss,sora[ss]=x,next[ss]=0; } void dfs(int x,int y) { ++w_time; rel[x]=low[x]=w_time; for (int i=x,ne;next[i];) { i=next[i],ne=sora[i]; if (rel[ne]) st[++top]=id[i]+n; } st[++top]=x; for (int i=x,ne;next[i];) { i=next[i],ne=sora[i]; if (po[i]==y) continue; if (rel[ne]) low[x]=min(low[x],rel[ne]); else { int tmp=top; dfs(ne,i); low[x]=min(low[x],low[ne]); if (low[ne]>=rel[x]) { flag[x]=flag[x+n+n]=1; ++block; //cout<<x<<' '<<top<<' '<<tmp<<endl; for (;top>tmp;top--) { b[st[top]]=block; // cout<<st[top]<<endl; if (st[top]<=n && flag[st[top]]) { link2(block,n+n+st[top]); // cout<<st[top]<<' '<<block<<endl; } } link2(block,n+n+x); top=tmp; } } } } void bfs(int s,int fl) { int h,r,ne,na; h=r=0; int k=(int)(log((double)n+n+n)/log(2.0))+1; st[r=1]=s,rel[s]=fl,d[s]=0; for (;h<r;) { ne=st[++h]; for (int i=ne;next[i];) { i=next[i],na=sora[i]; if (!rel[na]) { rel[na]=fl,d[na]=d[ne]+1; st[++r]=na; f[na][0]=ne,g[na][0]=flag[na]; } } } for (int j=1;j<=k;j++) for (int i=1;i<=r;i++) f[st[i]][j]=f[f[st[i]][j-1]][j-1], g[st[i]][j]=g[st[i]][j-1]+g[f[st[i]][j-1]][j-1]; ///cout<<r<<endl; //for (int i=1;i<=r;i++) cout<<st[i]<<' '<<f[st[i]][0]<<endl;cout<<endl; //cout<<f[7][0]<<endl; } int ask(int x,int y) { int e; //cout<<x<<' '<<y<<endl; if (d[x]<d[y]) e=x,x=y,y=e; e=d[x]-d[y]; int ans=0; for (int i=0;e;e>>=1,i++) if (e&1) ans+=g[x][i],x=f[x][i]; //cout<<x<<' '<<y<<endl; if (x==y) return ans+flag[x]; int k=0; for (;;) { if (f[x][k]==f[y][k]) { if (!k) break; k--; } else { ans+=g[x][k]+g[y][k]; x=f[x][k],y=f[y][k]; } } ans+=g[x][k]+g[y][k]; x=f[x][k],y=f[y][k]; return ans+flag[x]; } void origin() { ss=n+n+n; for (int i=1;i<=n+n+n;i++) tail[i]=i,next[i]=0; } int l[200000],r[200000]; int main() { freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); for (;;) { scanf("%d%d",&n,&m); if (!n && !m) break; origin(); for (int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); l[i]=x,r[i]=y; link(x,y,i); } for (int i=1;i<=n+n+n;i++) rel[i]=low[i]=flag[i]=d[i]=0; for (int i=1;i<=n+m;i++) b[i]=0; int k=(int)(log((double)n)/log(2.0))+1; for (int i=1;i<=n+n+n;i++) for (int j=0;j<=k;j++) f[i][j]=g[i][j]=0; top=0,w_time=0,block=n; for (int i=1;i<=n;i++) if (!rel[i]) dfs(i,0); //for (int i=1;i<=n+n+n;i++) cout<<flag[i]<<' ';cout<<endl; //for (int i=1;i<=n+m;i++) cout<<b[i]<<' ';cout<<endl; for (int i=n+1;i<=n+n;i++) if (!rel[i]) bfs(i,i); //for (int i=1;i<=n+n+n;i++) cout<<f[i][0]<<' ';cout<<endl; int q; scanf("%d",&q); for (int i=1;i<=n;i++) if (flag[i]) b[i]=i+n+n; for (;q;q--) { int x,y; scanf("%d%d",&x,&y); if ((b[x+n]==b[y+n]) || (rel[b[x+n]]!=rel[b[y+n]])) printf("0\n"); else { int ans=ask(b[x+n],b[y+n]); /* ans=min(ans,ask(b[l[x]],b[l[y]])-flag[l[x]]); ans=min(ans,ask(b[r[x]],b[l[y]])-flag[r[x]]); ans=min(ans,ask(b[l[x]],b[r[y]])-flag[l[x]]); ans=min(ans,ask(b[r[x]],b[r[y]])-flag[r[x]]);*/ printf("%d\n",ans); } } } return 0; }
拆边为点,考虑地更少
#include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <cmath> using namespace std; int ss,cnt,n,m,w_time,top,K,q; int st[250000],rel[250000],low[250000],d[250000],tail[250000]; int b[250000],w[250000]; int f[250000][20],g[250000][20]; int next[2000000],sora[2000000]; vector <int> vec[250000]; void link(int x,int y) { ++ss,next[tail[x]]=ss,tail[x]=ss,sora[ss]=y,next[ss]=0; ++ss,next[tail[y]]=ss,tail[y]=ss,sora[ss]=x,next[ss]=0; } void link2(int x,int y) { vec[x].push_back(y); vec[y].push_back(x); } void dfs(int x,int y) { ++w_time; rel[x]=low[x]=w_time; st[++top]=x; for (int i=x,ne;next[i];) { i=next[i],ne=sora[i]; if (ne==y) continue; if (rel[ne]) low[x]=min(low[x],rel[ne]); else { int tmp=top; dfs(ne,x); low[x]=min(low[x],low[ne]); if (low[ne]>=rel[x]) { b[x]=x; if (x<=n) w[x]=1; b[++cnt]=cnt; link2(x,cnt); for (;top!=tmp;top--) { int ne=st[top]; if (!b[ne]) b[ne]=cnt; link2(ne,cnt); } } } } } void dfs2(int x,int s,int dis) { low[x]=s; rel[x]=w_time; d[x]=dis; for (int i=0;i<vec[x].size();i++) { int ne=vec[x][i]; if (rel[ne]!=w_time) { f[ne][0]=x,g[ne][0]=w[x]; dfs2(ne,s,dis+1); } } } void origin() { ss=n+m; for (int i=1;i<=n+m;i++) tail[i]=i,next[i]=0; for (int i=1;i<=n+m;i++) rel[i]=low[i]=0; w_time=0,top=0; for (int i=1;i<=cnt;i++) vec[i].clear(); for (int i=1;i<=cnt;i++) w[i]=0,b[i]=0; cnt=n+m; } int ask(int x,int y) { if (low[x]!=low[y]) return 0; if (d[x]<d[y]) swap(x,y); int e=d[x]-d[y]; int sum=0; for (int b=0;e;e>>=1,b++) if (e&1) sum+=g[x][b],x=f[x][b]; if (x==y) return sum; for (int i=K;i>=0;i--) if (f[x][i]!=f[y][i]) { sum+=g[x][i]+g[y][i]; x=f[x][i],y=f[y][i]; } if (x!=y) sum+=g[x][0]; return sum; } int main() { for (;scanf("%d%d",&n,&m)==2;) { if (!n && !m) break; origin(); for (int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); link(x,i+n); link(i+n,y); } for (int i=1;i<=n+m;i++) if (!rel[i]) dfs(i,0); ++w_time; for (int i=1;i<=cnt;i++) if (rel[i]!=w_time) f[i][0]=0,g[i][0]=0,dfs2(i,i,0); K=(int)(log((double)cnt)/log(2.0))+1; for (int j=1;j<=K;j++) for (int i=1;i<=cnt;i++) f[i][j]=f[f[i][j-1]][j-1], g[i][j]=g[i][j-1]+g[f[i][j-1]][j-1]; scanf("%d",&q); // cout<<cnt<<endl; // cout<<f[7][0]<<' '<<f[8][0]<<' '<<f[6][0]<<endl; for (int i=1;i<=q;i++) { int x,y; scanf("%d%d",&x,&y); x+=n,y+=n; int ans=ask(x,y); printf("%d\n",ans); } } return 0; }
相关文章推荐
- [poj1144 Network]tarjan求割点
- [poj 1144]Network[Tarjan求割点]
- POJ 1144 Network 求割点(tarjan)
- 【POJ 1144】Network(Tarjan求割点)
- poj 1144 Network(模板题)(Tarjan 关节点的朴素算法)
- POJ 1144 Network 无向图求割点Tarjan
- [POJ1144][BZOJ2730]tarjan求割点
- POJ 1144 Network(Tarjan)
- POJ 1144 - Network 用tarjan求无向图的割点
- poj1144-tarjan求割点
- poj 1144 Network tarjan求无向连通图的割点个数
- POJ 1144 Network Tarjan 求无向图的割点的个数 Tarjan 模板题
- POJ1144 Network (Tarjan算法求无向图的割点)
- 【模板】【POJ1144】Network——tarjan求割点
- poj 1144 Network (tarjan割点模板)
- POJ 1144 Tarjan 割点 解题报告
- POJ 1144 Network ---tarjan算法求割点
- Poj 1144 Network【Tarjan求割点】
- poj 1144 Network (tarjan求割点)
- poj1144 - tarjan求割点