个人博客:在最前面发一下自己这个寒假刚弄的个人博客,很弱鸡,膜各位大佬。

在题干中划重点个节点条边的无向连通图且,所以这是一颗树呐。

再划重点:原图中所有初之外度为1的点,弱弱的问萌新们,这是什么点???叶子节点呐。

理清题意:每条边有一个边权,希望删除一些边使得叶子节点都不能到达点

明显的WA:萌新可能很容易想到把点到叶子节点路径上权值最小的边删掉,总代价就最小,很显然,这是错误的。提供反例:4 3 1,1 2 3,2 3 2,2 4 2。这棵树1为根节点,3和4分别为叶子节点,路径上权值最小的边都是2,总和为4,但显然最小代价为3。

正解
正解:如上图所示,假设点颗子树,对于每颗子树可以选择删除边,也可以选择删除子树中的边,两者取最小值即可。那怎么知道子树删哪些边呢???显然这是一个递归的套娃问题。而对于叶子节点我们取无穷大即可。

代码隐患:题目只说有权值并保证答案在c++ long long范围内,那么是不是权值可以为负呢?下面的代码并没有考虑这种情况,直接莽过了。

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const double pi = acos(-1);
const int mod = 1e9 + 7;
const double eps = 1e-8;
const int MAXN = 1e6 + 117;
const int MAXM = 2e5 + 117;

int n, m, s;
struct Edge {
    int v;
    LL w;
    int ne;
} edge[MAXN];
bool vis[MAXN];
int head[MAXN], tot;
void init() {
    tot = 0;
    memset(head, -1, sizeof(head));
    memset(vis, false, sizeof(vis));
}
void addedge(int u, int v, LL w) {
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].ne = head[u];
    head[u] = tot++;
}
LL dfs(int id) {
    vis[id] = true;
    LL ret = (LL)INF * INF, sum = 0, num;
    for(int i = head[id]; i != -1; i = edge[i].ne) {
        if(vis[edge[i].v]) continue;
        num = dfs(edge[i].v);
        sum += min(num, edge[i].w);
    }
    if(sum) return sum;
    return ret;
}
int main() {
    init();
    scanf("%d%d%d", &n, &m, &s);
    for(int i = 0; i < m; i++) {
        int u, v;
        LL w;
        scanf("%d%d%lld", &u, &v, &w);
        addedge(u, v, w);
        addedge(v, u, w);
    }
    printf("%lld\n", dfs(s));
    return 0;
}