【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;
}

posted @ 2021-01-28 12:39  Jayun  阅读(49)  评论(0编辑  收藏  举报