code:
/*
城市环路
树形dp + 环形dp
[没有上司的舞会]
基环树 -> 有一个环的树
一条边上两个点只能选一个 (父子互斥)
1. 找环 -> 不断去掉入度为1的叶子节点,最终只剩下环
拓扑排序
2.没有上司的舞会
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
int const N = 1e5 + 10;
double ans1 = 0, ans2 = 0;
vector<int> tree[N];
vector<int> circle;
int w[N];
long long f[N][2]; //选/不选 -> 0/1
int n;
double k;//?
void dp(int u, int fa)
{
f[u][1] = w[u];
f[u][0] = 0;
for(int x : tree[u])
{
if(x != fa)
{
dp(x, u);
f[u][0] += max(f[x][0], f[x][1]);
f[u][1] += f[x][0];
}
}
}
int main()
{
scanf("%d",&n);
for(int i = 0;i < n;i++) scanf("%d", &w[i]);
for(int u, v, i = 0;i < n;i++)
{
scanf("%d %d", &u, &v);
tree[u].push_back(v);
tree[v].push_back(u);
}
scanf("%lf", &k);
for(int i = 0; i < n; i++)
circle.push_back(i);
vector<int> out;
do
{
out.clear();
for(int i : circle)
{
if (tree[i].size() == 1)
{
out.push_back(i);
circle.erase(circle.begin() + i);
}
}
}while(out.size() != 0);
//找环
int root1 = circle[0], root2 = circle[1];
remove(tree[root1].begin(), tree[root1].end(), root2);
tree[root1].pop_back();
remove(tree[root2].begin(), tree[root2].end(), root1);
tree[root2].pop_back();
// 断边,转化为树
dp(root1, 0);
ans1 = f[root1][0];
dp(root2, 0);
ans2 = f[root2][0];
printf("%.1lf", max(ans1, ans2) * k);
return 0;
}
求助,附加数据全部T完(