Unleafy · blog

P1453 城市环路

416 words2 min readPageviews --#基环树
Categories题解Series题解 8/8

P1453 城市环路

题目大意

给定一棵基环树,选取一个点集,使得点集中的任意两点之间没有直接的连边,最大化 uSpu×k\sum_{u \in S} p_u \times k

解题思路

我们先找到这个基环树的环,然后随便找环上相邻的两点,假设为 u,vu, v,那么我们断开 u,vu, v 这条边,分别以 u,vu, v 为根跑 DP:

dpu,0=vson(u)max(dpv,0,dpv,1)dpu,1=vson(u)dpv,0\begin{aligned} dp_{u, 0} &= \sum_{v \in son(u)} \max(dp_{v, 0}, dp_{v, 1}) \\ dp_{u, 1} &= \sum_{v \in son(u)} dp_{v, 0} \end{aligned}

然后我们考虑最后的结果要么是取 uu 不取 vv,要么是取 vv 不取 uu,取最大值即可。

代码

#include <bits/stdc++.h>
using namespace std;
constexpr int N = 1e5 + 5;
int n, u, v, p[N], rt_u, rt_v;
long long dp[N][2];
bool vis[N];
vector<int> adj[N];
inline bool get_loop(int u, int fa) {
vis[u] = true;
for (auto v : adj[u]) {
if (v == fa) continue;
if (vis[v]) {
rt_u = u, rt_v = v;
return true;
}
if (get_loop(v, u)) return true;
}
return false;
}
inline void dfs(int u, int fa, int rt_u, int rt_v) {
dp[u][0] = 0;
dp[u][1] = p[u];
for (auto v : adj[u]) {
if (v == fa) continue;
if ((u == rt_u && v == rt_v) || (v == rt_u && u == rt_v)) continue;
dfs(v, u, rt_u, rt_v);
dp[u][0] += max(dp[v][0], dp[v][1]);
dp[u][1] += dp[v][0];
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> p[i];
for (int i = 1, u, v; i <= n; i++) {
cin >> u >> v;
u++, v++;
adj[u].push_back(v);
adj[v].push_back(u);
}
double k;
cin >> k;
get_loop(1, 0);
long long ans = 0;
dfs(rt_u, 0, rt_u, rt_v);
ans = max(ans, dp[rt_u][0]);
dfs(rt_v, 0, rt_u, rt_v);
ans = max(ans,dp[rt_v][0]);
cout << setiosflags(ios::fixed) << setprecision(1) << (double) ans * k << "\n";
return 0;
}

Comments

Quiet notes for this article.