Description
如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人图(cactus)。所谓简单回路就是指在图上不重复经过任何一个顶点的回路。
举例来说,上面的第一个例子是一张仙人图,而第二个不是——注意到它有三条简单回路:(4,3,2,1,6,5,4)、 (7,8,9,10,2,3,7)以及(4,3,7,8,9,10,2,1,6,5,4),而(2,3)同时出现在前两个的简单回路里。另外,第三张图也 不是仙人图,因为它并不是连通图。显然,仙人图上的每条边,或者是这张仙人图的桥(bridge),或者在且仅在一个简单回路里,两者必居其一。定义在图 上两点之间的距离为这两点之间最短路径的距离。定义一个图的直径为这张图相距最远的两个点的距离。现在我们假定仙人图的每条边的权值都是1,你的任务是求 出给定的仙人图的直径。
Input
输入的第一行包括两个整数n 和m(1≤n≤50000以及0≤m≤10000)。其中n代表顶点个数,我们约定图中的顶点将从1到n编号。接下来一共有m行。代表m条路径。每行的开 始有一个整数k(2≤k≤1000),代表在这条路径上的顶点个数。接下来是k个1到n之间的整数,分别对应了一个顶点,相邻的顶点表示存在一条连接这两 个顶点的边。一条路径上可能通过一个顶点好几次,比如对于第一个样例,第一条路径从3经过8,又从8返回到了3,但是我们保证所有的边都会出现在某条路径 上,而且不会重复出现在两条路径上,或者在一条路径上出现两次。
Output
只需输出一个数,这个数表示仙人图的直径长度。
Sample Input
9 1 2 3 4 5 6 7 8 3
7 2 9 10 11 12 13 10
5 2 14 9 15 10 8
10 1
10 1 2 3 4 5 6 7 8 9 10
Sample Output
HINT
对第一个样例的说明:如图,6号点和12号点的最短路径长度为8,所以这张图的直径为8。
TAT似乎是第一次写仙人掌类题目……刚开始一直再想“缩点dp缩点dp缩点dp”……结果发现多个环是可以共用一点的,缩点没法玩啊= =所以还是Link一下巨神们的题解吧= =
我自己模仿的很弱的实现:
2 Problem: 1023
3 User: AsmDef
4 Language: C++
5 Result: Accepted
6 Time:408 ms
7 Memory:8612 kb
8 ****************************************************************/
9
10 /***********************************************************************/
11 /**********************By Asm.Def-Wu Jiaxin*****************************/
12 /***********************************************************************/
13 #include <cstdio>
14 #include <cstring>
15 #include <cstdlib>
16 #include <ctime>
17 #include <cctype>
18 #include <algorithm>
19 #include <cmath>
20 using namespace std;
21 #define getc() getchar()
22 template<class T>inline void getd(T &x){
23 char ch = getc();bool neg = false;
24 while(!isdigit(ch) && ch != '-')ch = getc();
25 if(ch == '-')ch = getc(), neg = true;
26 x = ch - '0';
27 while(isdigit(ch = getc()))x = x * 10 - '0' + ch;
28 if(neg)x = -x;
29 }
30 /***********************************************************************/
31 #include <vector>
32 #include <queue>
33 #define pb push_back
34 #define pf push_front
35 const int maxn = 50005;
36 struct Edge{
37 int u, v, top, size;
38 void init(int a, int b){u = a, v = b;}
39 }E[maxn * 3], *Eend = E;
40 vector<Edge*>adj[maxn];
41 Edge *Last[maxn];
42 int dep[maxn], Ans, F[maxn], Stack[maxn], *Top = Stack;
43 bool istop[maxn];
44 struct Info{int val, id;Info(int a,int b){val = a, id = b;}};
45
46 inline void RollDP(int size){
47 int val[maxn<<1], N, i, mid = size >> 1, *it = val, Max = 0;
48 deque<Info> Q;
49 for(i = 0;i < size;++i)*it = F[Top[i]], Max = max(Max, min(i, size-i) + *(it++));
50 for(i = 0;i < mid;++i)*(it++) = F[Top[i]];
51 N = it - val;
52 Ans = max(Ans, *val);
53 Q.pb(Info(*val, 0));
54 for(i = 1;i < N;++i){
55 if(Q.front().id + mid < i)Q.pop_front();
56 Ans = max(Ans, Q.front().val + val[i] + i);
57 Info tmp(val[i]-i, i);
58 while(!Q.empty() && Q.back().val <= tmp.val)Q.pop_back();
59 Q.push_back(tmp);
60 }
61 F[*Top] = Max;
62 }
63
64 void dfs(int cur){
65 static bool vis[maxn];vis[cur] = true;
66 vector<Edge*>::iterator it;
67 for(it = adj[cur].begin();it != adj[cur].end();++it){
68 Edge &e = **it;
69 if(Last[cur] && e.v == Last[cur]->u)continue;
70 if(vis[e.v]){
71 if(dep[e.v] > dep[cur])continue;
72 Edge *t = &e;
73 int top = e.v, s = dep[cur] - dep[top] + 1;
74 do{
75 *(Top++) = t->v;
76 t->top = top, t->size = s;
77 t = Last[t->u];
78 }while(t && t->v != top);
79 }
80 else{
81 Last[e.v] = &e, dep[e.v] = dep[cur] + 1;
82 dfs(e.v);
83 if(!e.top){
84 Ans = max(Ans, F[cur] + F[e.v] + 1);
85 F[cur] = max(F[cur], F[e.v] + 1);
86 }
87 else if(e.top == cur){
88 while(*(--Top) != cur);
89 RollDP(e.size);
90 }
91 }
92 }
93 }
94
95 inline void work(){
96 int N, M, k, u, v;
97 getd(N);getd(M);
98 while(M--){
99 getd(k);getd(v);
100 while(--k){
101 u = v;getd(v);
102 Eend->init(u, v);adj[u].pb(Eend++);
103 Eend->init(v, u);adj[v].pb(Eend++);
104 }
105 }
106 dfs(1);
107 }
108
109
110
111 int main(){
112 work();
113 printf("%d ", Ans);
114
115 #ifdef DEBUG
116 printf(" %.2lf sec ", (double)clock() / CLOCKS_PER_SEC);
117 #endif
118 return 0;
119 }
120