Rinne Loves Edges
Rinne 最近了解了如何快速维护可支持插入边删除边的图,并且高效的回答一下奇妙的询问。
她现在拿到了一个 n 个节点 m 条边的无向连通图,每条边有一个边权 (w_i)
现在她想玩一个游戏:选取一个 “重要点” S,然后选择性删除一些边,使得原图中所有除 S 之外度为 1 的点都不能到达 S。
定义删除一条边的代价为这条边的边权,现在 Rinne 想知道完成这个游戏的最小的代价,这样她就能轻松到达 rk1 了!作为回报,她会让你的排名上升一定的数量。
链接:https://ac.nowcoder.com/acm/problem/22598
来源:牛客网
树形dp。
对于节点cur, 其最小代价为直接删除与孩子节点相连的边或由其孩子节点断掉和叶子节点的联系.即:
[dp[cur] = min(dp[child], dist[cur][child])
]
但是这是一颗树,我们没办法直接以递推的形式从小问题开始解决,但是利用递归我们可以完成这个操作。从根节点开始dfs,一直到叶子节点退回来计算dp值。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
typedef long long ll;
class Edge{
public:
ll to, len;
};
vector<Edge> v[N];
ll dp[N];
void dfs(int cur,int father){
int b = 0;
for(int i = 0;i < v[cur].size(); i++){
ll to = v[cur][i].to, len = v[cur][i].len;
if(to == father)continue;
b = 1;
dfs(to, cur);
dp[cur] += min(dp[to], len);
}
if(!b)dp[cur] = 0x7f7f7f7f;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m, s;
cin >> n >> m >> s;
for(int i = 0;i < m; i++){
int x, y, z;
cin >> x >> y >> z;
v[x].push_back({y, z});
v[y].push_back({x, z});
}
dfs(s, 0);
cout << dp[s] << endl;
}