给定树T = (V,E),如果每个顶点都有一个权重,称为权值,使用C++贪心算法来计算最大的权值和,如果一个顶点已经被选中,那么它的相邻顶点不能被选中。
时间: 2024-01-21 22:04:07 浏览: 125
好的,那我们先来看一下原代码,这是一个求树的独立集的问题,即选出一些点使得这些点两两不相邻,且权值和最大。
```C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = 10010;
struct Node {
int id;
int w;
bool operator < (const Node& a) const {
return w > a.w;
}
};
vector<Node> G[MAXN];
bool vis[MAXN];
void dfs(int u, int fa) {
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i].id;
if (v == fa) continue;
dfs(v, u);
if (!vis[v]) vis[u] = true;
}
}
int main() {
int n, u, v, w;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> w;
G[i].push_back({i, w});
}
for (int i = 1; i < n; i++) {
cin >> u >> v;
G[u].push_back({v, 0});
G[v].push_back({u, 0});
}
dfs(1, 0);
int ans = 0;
for (int i = 1; i <= n; i++) {
if (!vis[i]) ans += G[i][0].w;
}
cout << ans << endl;
return 0;
}
```
那么我们需要修改的,就是将求独立集的问题转换为求最大权值和问题。在原代码中,我们可以看到,对于每个点,它有自己的权值,而对于边,它们的权值都为0。
我们可以将这个问题转化为,对于每个点,选或不选,如果选了这个点,那么它的相邻点都不能选,最终要使得选中的点的权值和最大。
修改后的代码如下:
```C++
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 10010;
struct Node {
int w;
vector<int> son;
} node[MAXN];
int f[MAXN][2];
void dfs(int u, int fa) {
f[u][0] = 0;
f[u][1] = node[u].w;
for (int i = 0; i < node[u].son.size(); i++) {
int v = node[u].son[i];
if (v == fa) continue;
dfs(v, u);
f[u][0] += max(f[v][0], f[v][1]);
f[u][1] += f[v][0];
}
}
int main() {
int n, u, v, w;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> w;
node[i].w = w;
}
for (int i = 1; i < n; i++) {
cin >> u >> v;
node[u].son.push_back(v);
node[v].son.push_back(u);
}
memset(f, 0, sizeof(f));
dfs(1, 0);
cout << max(f[1][0], f[1][1]) << endl;
return 0;
}
```
我们使用f[u][0]表示不选u的最大权值和,f[u][1]表示选u的最大权值和。最终的答案就是max(f[1][0], f[1][1]),即根节点的最大权值和。
阅读全文