以最小代价隔离加权树中的一些顶点

Isolating some vertices in a weighted tree with minimum cost

本文关键字:顶点 加权 代价 隔离      更新时间:2023-10-16

假设我们得到一个加权树和该树的一些顶点集。问题是通过从树中移除边来隔离这些顶点(例如,它们之间不应该有路径(,使得移除的边的权重之和最小。

我已经试着解决这个问题大约两个小时了,然后我在C++中找到了解决方案,但没有任何解释。据我所知,它使用了动态编程技术。

我的问题是,解决这个问题的基本思路是什么?

谢谢!

这是解决方案。

#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
#define PB push_back
#define MP make_pair
typedef long long LL;
const int MAXN = 100005;
const LL inf = 1LL << 55;
int N, K;
bool bad[MAXN];
LL dp[MAXN][2];
vector<pair<int, int> > adj[MAXN];
void dfs(int u, int fa) {
    dp[u][1] = 0;
    dp[u][0] = bad[u] ? inf : 0;
    for (int i = 0; i < adj[u].size(); i++) {
        int v = adj[u][i].first, w = adj[u][i].second;
        if (v != fa) {
            dfs(v, u);
            dp[u][1] += min(dp[v][0], dp[v][1] + w);
            dp[u][1] = min(dp[u][1], dp[u][0] + dp[v][1]);
            if (!bad[u])
                dp[u][0] += min(dp[v][0], dp[v][1] + w);
        }
    }
}
int main() {
    cin >> N >> K;
    for (int i = 1; i < N; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        adj[a].PB(MP(b, c)); adj[b].PB(MP(a, c));
    }
    memset(bad, false, sizeof(bad));
    for (int i = 0; i < K; i++) {
        int x;
        cin >> x;
        bad[x] = true;
    }
    dfs(0, -1);
    LL ret = min(dp[0][0], dp[0][1]);
    cout << ret << endl;
    return 0;
}

形式上,问题是,给定一个具有加权边的非循环无向图,以及一组终端顶点,找到最小边集,其移除意味着,对于所有不同终端对,这些终端不再连接。

任意求图的根,并将其视为一般树。我们运行一个动态程序,该程序在顶点上自下而上进行操作。每个顶点u都有两个标签:dp[u][0]是以u为根的子树中要移除的边的最小权重,使得子树中没有端子连接到另一个端子或连接到u,而dp[u][1]是只留下一个子树端子连接到u的最小移除权重。我们有一个复发

           { infinity                  if v is a terminal
dp[u][0] = {       sum       dp[v][0]  otherwise
           { children v of u
dp[u][1] =       min       dp[v][1] +          sum          min(dp[w][0], dp[w][1] + weight(uw)),
           children v of u            other children w of v

取空min为CCD_ 7。