今天考试写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)枚举判断分叉即可。


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的连通块就好了。


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。
今天用缩点试了一下,时间快了很多哈,虽然代码长度几乎是前者的两倍。


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