链接:https://ac.nowcoder.com/acm/problem/22598
来源:牛客网
题目描述
Rinne 最近了解了如何快速维护可支持插入边删除边的图,并且高效的回答一下奇妙的询问。
她现在拿到了一个 n 个节点 m 条边的无向连通图,每条边有一个边权 wi
现在她想玩一个游戏:选取一个 “重要点” S,然后选择性删除一些边,使得原图中所有除 S 之外度为 1 的点都不能到达 S。
定义删除一条边的代价为这条边的边权,现在 Rinne 想知道完成这个游戏的最小的代价,这样她就能轻松到达 rk1 了!
作为回报,她会让你的排名上升一定的数量。
输入描述:
第一行三个整数 N,M,S,意义如「题目描述」所述。
接下来 M 行,每行三个整数 u,v,w 代表点 u 到点 v 之间有一条长度为 w 的无向边。
输出描述:
一个整数表示答案。
示例1
输入
4 3 1
1 2 1
1 3 1
1 4 1
输出
3
示例2
输入
4 3 1
1 2 3
2 3 1
3 4 2
输出
1
备注:
2≤S≤N≤10e5,M=N−1,保证答案在 C++ long long 范围内。
题解部分
今天是第一次写题解,也是第一次在牛客每日一题上做对一道题,大家多多关照。
这道题是一道树上dp
注意题目条件,M = N - 1在暗示我们这是一颗树,所以除 S 之外度为 1 的点就是以S为根的叶节点
题目就是让我们求删去最少权值的边来让S和叶节点不连通
若我们设f[x]表示以x为子树中叶节点与S不连通需要的最小代价,所以f[x] = min(f[y],len[x][y])
其中y表示x的儿子,len[x][y]表示x到y的距离
注意,f[x]要加上儿子的最小代价和
附上代码(我没开long long竟然过了)
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 3e5 + 5;
int Last[MAXN],Next[MAXN],Len[MAXN],End[MAXN],cnt,f[MAXN];
void add(int x,int y,int z)
{
End[++cnt] = y;Next[cnt] = Last[x];Last[x] = cnt,Len[cnt] = z;
}
int dfs(int x,int fa)
{
int ans = 0;
for(int i = Last[x];i;i = Next[i])
{
int y = End[i];
if(y != fa)
{
ans++;
if(dfs(y,x) == 0)
f[y] = Len[i];
f[x] += min(f[y],Len[i]);
}
}
return ans;
}
int main()
{
int n,m,s;
scanf("%d %d %d", &n, &m, &s);
for(int i = 1;i <= m; i++)
{
int x,y,z;
scanf("%d %d %d", &x ,&y, &z);
add(x,y,z);
add(y,x,z);
}
dfs(s,0);
printf("%d", f[s]);
return 0;
}
祝大家A题愉快