洛谷 P1453 城市环路

原题链接

n个点n条边,题目保证连通,所以原图是个无向的基环树,考虑基环树dp

这题可以用树形dp + 环形dp实现。

首先把环给找出来,然后对于环上的每个点u,做以u为根节点的树形dp(类似没有上司的舞会)。

然后做环形dp,需要注意两点:

1、转移的顺序是dfs

2、因为是环,起点和终点的状态不能冲突,所以需要枚举起点的状态,求两遍环形dp取最大值

#include<bits/stdc++.h>
using namespace std;
#define fr first
#define se second
#define et0 exit(0);
#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)
#define rrep(i, a, b) for(int i = (int)(a); i >= (int)(b); i --)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
typedef unsigned long long ULL;
const int INF = 0X3f3f3f3f, N = 1e5 + 10, MOD = 1e9 + 7;
const double eps = 1e-7, pi = acos(-1);
int n;
double k;
int p[N];
int head[N], idx;
struct EGDE {
int to, next;
} eg[N << 1];
void add(int x, int y) {
eg[idx].to = y;
eg[idx].next = head[x];
head[x] = idx++;
}
int d[N], st[N]; // u不在环上: st[u] == true
void find_c() {
queue<int> q;
rep(i, 0, n - 1) if (d[i] == 1) q.push(i);
while (!q.empty()) {
int u = q.front();
q.pop();
st[u] = true;
for (int i = head[u]; ~i; i = eg[i].next) {
int to = eg[i].to;
if (st[to]) continue;
if (--d[to] == 1) q.push(to);
}
}
}
int f[N][2];
void DP_1(int u, int fa) {
f[u][1] = p[u];
for (int i = head[u]; ~i; i = eg[i].next) {
int to = eg[i].to;
if (to == fa || st[to] == false) continue;
DP_1(to, u);
f[u][0] += max(f[to][1], f[to][0]);
f[u][1] += f[to][0];
}
}
int Start, cnt, dfs_id[N];
void dfs(int u, int fa) {
dfs_id[++cnt] = u;
for (int i = head[u]; ~i; i = eg[i].next) {
int to = eg[i].to;
if (to == fa || st[to] || to == Start) continue;
dfs(to, u);
break;
}
}
int dp[N][2], ans;
void DP_2() {
memset(dp, 0xcf, sizeof dp);
dp[1][1] = f[dfs_id[1]][1];
rep(i, 2, cnt) {
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1]) + f[dfs_id[i]][0];
dp[i][1] = dp[i - 1][0] + f[dfs_id[i]][1];
}
ans = dp[cnt][0];
memset(dp, 0xcf, sizeof dp);
dp[1][0] = f[dfs_id[1]][0];
rep(i, 2, cnt) {
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1]) + f[dfs_id[i]][0];
dp[i][1] = dp[i - 1][0] + f[dfs_id[i]][1];
}
ans = max(ans, max(dp[cnt][0], dp[cnt][1]));
}
void work() {
memset(head, -1, sizeof head);
scanf("%d", &n);
rep(i, 0, n - 1) scanf("%d", p + i);
rep(i, 0, n - 1) {
int x, y;
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
d[x]++, d[y]++;
}
scanf("%lf", &k);
//找环
find_c();
Start = -1;
rep(i, 0, n - 1) {
if (!st[i]) {
DP_1(i, -1);
if (Start == -1) Start = i;
}
}
dfs(Start, -1);
DP_2();
printf("%.1lf\n", ans * k);
}
signed main() {
int test = 1;
// cin >> test;
while (test--) {
work();
}
return 0;
}

本文作者:xhy666

本文链接:https://www.cnblogs.com/xhy666/p/16549063.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   xhy666  阅读(31)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起