【问题标题】:Isolating some vertices in a weighted tree with minimum cost以最小成本隔离加权树中的一些顶点
【发布时间】:2015-08-14 12:33:23
【问题描述】:

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

我一直在尝试解决这个问题大约两个小时,然后我在 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;
}

【问题讨论】:

  • 这真是糟糕的 C++ 代码..
  • 能否请您也发布确切的问题说明? “隔离那些顶点”到底是什么意思?应该没有从根到它们的路径,或者我们应该有一个连接的组件(或更多?),其中只有孤立的顶点(它们)?
  • 你所说的树,是指二叉树、N叉树还是“通用树”(有根连通无环图)?二叉树会(编辑:可能)大大简化问题(我仍然难以理解您发布的代码的意图,变量的命名真的很糟糕)。
  • 一般树。它是有竞争力的程序员的代码。这就是为什么它的名字如此糟糕的原因:)

标签: c++ algorithm dynamic-programming


【解决方案1】:

正式地,问题是,给定一个带有加权边的无环无向图,连同一组 终端 顶点,找到最小的边集,其去除意味着,对于所有不同的终端对,这些终端不再连接。

任意根图,将其视为一般树。我们运行一个在顶点上自下而上操作的动态程序。每个顶点u 有两个标签:dp[u][0] 是在以u 为根的子树中要删除的边的最小权重,这样子树中的任何终端都不会连接到另一个终端或u 和@987654325 @ 是仅留下一个连接到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

取一个空的最小值为infinity

【讨论】:

  • 有一个小错误:“dp[u][1] 是仅留下一个子树终端连接到u 的最小移除权重”,实际上不是“完全”而是“最多”(该子树中可能没有任何终端节点)但我在吹毛求疵。否则很好的答案(但我觉得现在重命名和评论 OP 的代码有点愚蠢......)
猜你喜欢
  • 1970-01-01
  • 2015-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-04
  • 2012-09-27
  • 1970-01-01
  • 2021-09-26
相关资源
最近更新 更多