Blog of RuSun

\begin {array}{c} \mathfrak {One Problem Is Difficult} \\\\ \mathfrak {Because You Don't Know} \\\\ \mathfrak {Why It Is Diffucult} \end {array}

P6335 [COCI2007-2008#1] STAZA

P6335 [COCI2007-2008#1] STAZA

考虑DP。考虑对于一个点路线的过程,一定是先将一些环走完,回到当前这个点,再选择一条路径继续走,不再回来。$f _ i$ 表示从 $i$ 走,在 $i$ 的子仙人掌内,最终回到 $i$ 点的最长路线;$g _ i$ 表示从 $i$ 走,在 $i$ 的子仙人掌内最长路线。出边分为两种:一种是桥,一旦选择走桥就不能回来;另一种是环,可以回来,也可以选择不再回来。$f _ i$ 是确定的,即将所有环走完;先考虑选择所有环后只从桥走出,那么答案为 $f _ i + k$ ,$k$ 表示走桥后最大的 $g _ j$ 。考虑将某个环中途放弃回来,那么求出 $\Delta$ 和 $k$ 取最大值。$g _ i = f _ i + \max \Delta$ 。

查看代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <cstdio>
#include <vector>
#define pb push_back
using namespace std;
template <class Type>
void read (Type &x)
{
char c;
bool flag = false;
while ((c = getchar()) < '0' || c > '9')
c == '-' && (flag = true);
x = c - '0';
while ((c = getchar()) >= '0' && c <= '9')
x = (x << 1) + (x << 3) + c - '0';
flag && (x = ~x + 1);
}
template <class Type, class ...rest>
void read (Type &x, rest &...y) { read(x), read(y...); }
template <class Type>
void write (Type x)
{
x < 0 && (putchar('-'), x = ~x + 1);
x > 9 && (write(x / 10), 0);
putchar('0' + x % 10);
}
const int N = 1e4 + 10;
int n, m, d[N], p[N], f[N], g[N];
vector <int> e[N];
int stmp, dfn[N], low[N];
void tarjan (int u)
{
int k = 0;
dfn[u] = low[u] = ++stmp;
for (int v : e[u]) if (v ^ p[u])
if (!dfn[v])
{
d[v] = d[u] + 1; p[v] = u;
tarjan(v);
low[u] = min(low[u], low[v]);
if (low[v] > dfn[u]) k = max(k, g[v] + 1);
}
else low[u] = min(low[u], dfn[v]);
for (int v : e[u]) if (dfn[v] > dfn[u] && p[v] ^ u)
{
int s = 1, t = 0;
for (int i = v; i ^ u; i = p[i])
t = max(t, s + g[i]), s += f[i] + 1;
f[u] += s;
for (int i = v, c = s; i ^ u; i = p[i])
c -= f[i] + 1, t = max(t, c + g[i]);
k = max(k, t - s);
}
g[u] = f[u] + k;
}
int main ()
{
read(n, m);
for (int a, b; m; --m)
read(a, b), e[a].pb(b), e[b].pb(a);
tarjan(1);
write(g[1]);
return 0;
}