强连通 tarjan

今天考试写Tarjan挂掉了,T_T太水了。

找了POJ的两题做做。

voidtarjan(int u)

{

    DFN[u]=Low[u]=++index;S[++Scnt]=u;inS[u]=1;

     for (int j=edg[u];j!=0;j=E[j].next)

     {

         int v=E[j].y;

         if (DFN[v]==0)

         {

                       tarjan(v);

                       if (Low[v]<Low[u])Low[u]=Low[v];

         }

         else

         if (inS[v]==1 &&Low[v]<Low[u]) Low[u]=DFN[v];

     }

     if (DFN[u]==Low[u])

     {

        ++col;

        /*

        while (Scnt>0 && Low[S[Scnt]]==Low[u])

        {

              color[S[Scnt]]=col;

              inS[S[Scnt] ]=0;

              --Scnt;

        }

        !!!注意这里的错误  为什么呢,Low的更新于边的顺序有关,不能保证

    Low[v]=Low[u] (u为连通块里,标号最低的点。

        */

        while (S[Scnt] !=u)

        {

              color[S[Scnt]]=col;

              inS[S[Scnt] ]=0;

              --Scnt;

        }

        color[S[Scnt]]=col;

              inS[S[Scnt] ]=0;

              --Scnt;

     }

}

---------------------------------------------------------------------------------

http://poj.org/problem?id=2762

题目大意:给你一个图,让你求强连通缩点,看是不是剩下一条链。

做法:显然Tarjan完之后缩点,接着就判图弱连通(入度为0的个数只能有一个)

再O(n)枚举判断分叉即可。

代码
1 #include<iostream>
2 #include<cstdio>
3  #define N 2000
4  #define M 10000
5  using namespace std;
6 struct node{
7 int y,next;
8 } E[M];
9 int edg[N],S[N],inS[N],DFN[N],Low[N],color[N],next[N],in[N];
10 int index,col,T,cnt,n,m,x[M],y[M],Scnt;
11 void add_edge(int x,int y)
12 {
13 ++cnt;E[cnt].y=y;E[cnt].next=edg[x];edg[x]=cnt;
14 }
15 void tarjan(int u)
16 {
17 DFN[u]=Low[u]=++index;S[++Scnt]=u;inS[u]=1;
18 for (int j=edg[u];j!=0;j=E[j].next)
19 {
20 int v=E[j].y;
21 if (DFN[v]==0)
22 {
23 tarjan(v);
24 if (Low[v]<Low[u]) Low[u]=Low[v];
25 }else
26 if (inS[v]==1 && Low[v]<Low[u]) Low[u]=Low[v];
27 }
28 if (DFN[u]==Low[u])
29 {
30 ++col;
31 while (S[Scnt]!=u)
32 {
33 color[S[Scnt]]=col;
34 inS[S[Scnt]]=0;
35 --Scnt;
36
37 }
38 color[S[Scnt]]=col;
39 inS[S[Scnt]]=0;
40 --Scnt;
41 }
42 }
43 int main()
44 {
45 freopen("2762.in","r",stdin);
46 freopen("2762.out","w",stdout);
47 scanf("%d",&T);
48 for (int ii=1;ii<=T;++ii)
49 {
50 scanf("%d%d",&n,&m);
51
52 //init;
53 cnt=0;col=0;index=0;
54 for (int i=1;i<=n;++i) edg[i]=DFN[i]=Low[i]=color[i]=in[i]=0;
55 for (int i=1;i<=m;++i)
56 {
57 scanf("%d%d",&x[i],&y[i]);
58 add_edge(x[i],y[i]);
59 }
60 for (int i=1;i<=n;++i)
61 if (DFN[i]==0) tarjan(i);
62
63 for (int i=1;i<=col;++i) next[i]=-1;
64
65 // for (int i=1;i<=n;++i) printf("%d %d\n",i,color[i]);
66 int flag=1,cc=0;
67 for (int i=1;i<=m;++i) ++in[color[y[i]]];
68
69 for (int i=1;i<=col;++i)
70 if (in[i]==0) ++cc;
71 if (cc>1) flag=0;
72 if (flag)
73 for (int i=1;i<=m;++i)
74 if (color[x[i]]!=color[y[i]])
75 {
76 if (next[color[x[i]]]==-1) next[color[x[i]]]=color[y[i]];
77 if (next[color[x[i]]]!=color[y[i]])
78 {
79 flag=0;break;
80 }
81 }
82 if (flag==1) printf("Yes\n"); else printf("No\n");
83 }
84 return 0;
85 }
86

----------------------------------------------------------------------------------

http://poj.org/problem?id=2553

题目大意:求强连通,并且该连通出度为0

做法:强连通缩点完,求出所有出度为0的连通块就好了。

代码
1 #include<iostream>
2 #include<cstdio>
3 #define N 50001
4 using namespace std;
5 struct node{
6 int y,next;
7 } E[1000000];
8
9 int edg[N],x[N],y[N],bo[N],S[N],inS[N],DFN[N],Low[N],color[N];
10 int cnt,index,Scnt,col;
11 int n,m;
12 void add_edge(int x,int y)
13 {
14 ++cnt;E[cnt].y=y;E[cnt].next=edg[x];edg[x]=cnt;
15 }
16 void tarjan(int u)
17 {
18 DFN[u]=Low[u]=++index;S[++Scnt]=u;inS[u]=1;
19
20 for (int j=edg[u];j!=0;j=E[j].next)
21 {
22 int v=E[j].y;
23 if (DFN[v]==0)
24 {
25 tarjan(v);
26 if (Low[v]<Low[u]) Low[u]=Low[v];
27 }
28 else
29 if (inS[v]==1 && Low[v]<Low[u]) Low[u]=DFN[v];
30 }
31
32 if (DFN[u]==Low[u])
33 {
34 ++col;
35 /*
36 while (Scnt>0 && Low[S[Scnt] ]==Low[u])
37 {
38 color[S[Scnt]]=col;
39 inS[S[Scnt] ]=0;
40 --Scnt;
41
42 }
43 !!!注意这里的错误
44 */
45 while (S[Scnt] !=u)
46 {
47 color[S[Scnt]]=col;
48 inS[S[Scnt] ]=0;
49 --Scnt;
50 }
51 color[S[Scnt]]=col;
52 inS[S[Scnt] ]=0;
53 --Scnt;
54 }
55
56 }
57 int main()
58 {
59 freopen("2553.in","r",stdin);
60 freopen("2553.out","w",stdout);
61 scanf("%d",&n);
62 while (n>0)
63 {
64 scanf("%d",&m);
65 cnt=0;index=0;col=0;
66 for (int i=1;i<=n;++i) edg[i]=0;
67 for (int i=1;i<=n;++i) DFN[i]=Low[i]=color[i]=0,bo[i]=1;
68
69 for (int i=1;i<=m;++i)
70 {
71 scanf("%d%d",&x[i],&y[i]);
72 add_edge(x[i],y[i]);
73 }
74 for (int i=1;i<=n;++i)
75 if (DFN[i]==0) tarjan(i);
76
77 for (int i=1;i<=col;++i) bo[i]=1;
78
79 for (int i=1;i<=m;++i)
80 {
81 if (color[x[i]]!=color[y[i]])
82 bo[color[x[i] ] ]=0;
83 }
84
85
86 int i;
87 for (i=1;i<=n;++i)
88 if (bo[color[i]]) {printf("%d",i);break;}
89 for (i=i+1;i<=n;++i)
90 if (bo[color[i]]) {printf(" %d",i);}
91 printf("\n");
92 scanf("%d",&n);
93 }
94
95 return 0;
96 }
97

----------------------------------------------------------------------------------

题目:NOIP2009 trade

先前用的是起点开始spfa,然后终点退回来spfa。

今天用缩点试了一下,时间快了很多哈,虽然代码长度几乎是前者的两倍。

代码
1 /*
2 algorithm:
3 tarjan缩点,拓扑排序后一遍更新即可。
4 up[],down[],ans[]分别表示从起点到该点的最大值,最小值,和最大答案
5  */
6 #include<iostream>
7 #include<cstdio>
8  #define N 100100
9  #define M 1000001
10  #define INF 100000000
11  using namespace std;
12  struct node{
13 int y,next;
14 } E[M];
15
16  int cnt,index,Scnt,x[M],y[M],z[M],col,head,tail,n,m,u,v;
17  int DFN[N],Low[N],S[N],inS[N],edg[N],color[N],in[N],Q[N],c[N],up[N],down[N],vis[N],ans[N];
18  void add_edge(int x,int y)
19 {
20 ++cnt;E[cnt].y=y;E[cnt].next=edg[x];edg[x]=cnt;
21 }
22  void tarjan(int u)
23 {
24 DFN[u]=Low[u]=++index;S[++Scnt]=u;inS[u]=1;
25 for (int j=edg[u];j!=0;j=E[j].next)
26 {
27 int v=E[j].y;
28 if (DFN[v]==0)
29 {
30 tarjan(v);
31 if (Low[v]<Low[u]) Low[u]=Low[v];
32 }else
33 if (inS[v]==1 && DFN[v]<Low[u]) Low[u]=DFN[v];
34 }
35 if (DFN[u]==Low[u])
36 {
37 ++col;
38 while (S[Scnt]!=u)
39 {
40 color[S[Scnt]]=col;
41 inS[S[Scnt]]=0;
42 --Scnt;
43 }
44 color[S[Scnt]]=col;
45 inS[S[Scnt]]=0;
46 --Scnt;
47 }
48 }
49  int main()
50 {
51 freopen("trade.in","r",stdin);
52 freopen("trade.out","w",stdout);
53 scanf("%d %d",&n,&m);
54 for (int i=1;i<=n;++i) scanf("%d",&c[i]);
55
56 for (int i=1;i<=m;++i)
57 {
58 scanf("%d%d%d\n",&x[i],&y[i],&z[i]);
59 add_edge(x[i],y[i]);
60 if (z[i]==2)
61 add_edge(y[i],x[i]);
62 }
63 for (int i=1;i<=n;++i)
64 if (DFN[i]==0) tarjan(i);
65
66 cnt=0;
67 // for (int i=1;i<=n;++i) printf("%d %d\n",i,color[i]);
68
69 for (int i=1;i<=col;++i) edg[i]=0;
70 for (int i=1;i<=m;++i)
71 {
72 if (color[x[i]]==color[y[i]]) continue;
73 add_edge(color[x[i]],color[y[i]]);++in[color[y[i]]];
74 if (z[i]==2)
75 add_edge(color[y[i]],color[x[i]]),++in[color[x[i]]];
76 }
77
78 //topology
79 for (int i=1;i<=col;++i)
80 if (in[i]==0) {Q[++tail]=i;}
81 while (head<tail)
82 {
83 u=Q[++head];
84 for (int j=edg[u];j!=0;j=E[j].next)
85 {
86 v=E[j].y;
87 --in[v];
88 if (in[v]==0) Q[++tail]=v;
89 }
90 }
91
92 head=1;while (Q[head]!=color[1]) ++head;
93
94 for (int i=1;i<=col;++i) up[i]=-INF,down[i]=INF;
95
96 for (int i=1;i<=n;++i)
97 {
98 if (c[i]>up[color[i]]) up[color[i]]=c[i];
99 if (c[i]<down[color[i]]) down[color[i]]=c[i];
100 if (ans[color[i]]<up[color[i]]-down[color[i]]) ans[color[i]]=up[color[i]]-down[color[i]];
101 }
102 //for (int i=1;i<=col;++i) printf("$%d %d\n",up[i],down[i]);
103
104 while (head<=tail)
105 {
106 u=Q[head];
107 for (int j=edg[u];j!=0;j=E[j].next)
108 {
109 v=E[j].y;
110 if (up[v]-down[u]>ans[v]) ans[v]=up[v]-down[u];
111 if (down[u]<down[v]) down[u]=down[v];
112 if (ans[u]>ans[v]) ans[v]=ans[u];
113 }
114 ++head;
115 }
116 cout<<ans[color[n]]<<endl;
117
118 return 0;
119 }
120
posted @ 2010-11-16 20:37  Whimsy  阅读(307)  评论(0编辑  收藏  举报