强连通 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)枚举判断分叉即可。

ContractedBlock.gif ExpandedBlockStart.gif 代码
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的连通块就好了。

ContractedBlock.gif ExpandedBlockStart.gif 代码
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。

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

ContractedBlock.gif ExpandedBlockStart.gif 代码
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

转载于:https://www.cnblogs.com/LitIce/archive/2010/11/16/1878846.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值