【Luogu P1453】城市环路
链接:
题目大意:
求基环树的最大独立集。
正文:
按照题目大意所述求出给出基环树的最大独立集。我们可以先找环,看作是把一条多余的边去掉,在原本环上的两点跑两遍树的最大独立集。和 【Luogu P2607】[ZJOI2008]骑士 不同的是,这题的基环树是联通的,没有基环树森林。
代码:
const int N = 1e5 + 5;
int n;
int head[N], to[N << 1], next[N << 1], score[N << 1];
int tot;
double ans;
double k;
double f[N][2];
void ADD(int u, int v)
{
to[++tot] = v, next[tot] = head[u], head[u] = tot;
}
void DP(int node, int fa)
{
f[node][1] = score[node];
f[node][0] = 0;
for (int i = head[node]; i; i = next[i])
{
int v = to[i];
if (v != fa)
{
DP(v, node);
f[node][0] += max(f[v][0], f[v][1]);
f[node][1] += f[v][0];
}
}
}
int fa[N], S, T;
int Find(int x) {return fa[x] == x? x: fa[x] = Find(fa[x]);}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
scanf ("%d", &n);
for (int i = 1; i <= n; i++) fa[i] = i;
for (int i = 1; i <= n; i++)
scanf ("%d", &score[i]);
for (int i = 1; i <= n; i++)
{
int u, v;
scanf ("%d%d", &u, &v), u++, v++;
if (Find(u) == Find(v)) {S = u, T = v; continue;}
ADD(u, v);
ADD(v, u);
fa[Find(v)] = Find(u);
}
scanf ("%lf", &k);
DP (S, 0); ans = f[S][0];
DP (T, 0); ans = max(ans, f[T][0]);
printf ("%.1lf\n", ans * k);
return 0;
}