题目描述
Rinne 最近了解了如何快速维护可支持插入边删除边的图,并且高效的回答一下奇妙的询问。
她现在拿到了一个 n 个节点 m 条边的无向连通图,每条边有一个边权 wiw_iwi
现在她想玩一个游戏:选取一个 “重要点” 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,3,4 不能到达点 1,显然只能删除所有的边,答案为 3
示例2
输入
4 3 1 1 2 3 2 3 1 3 4 2
输出
1
说明
需要使得点 4 不能到达点 1,显然删除边 2↔3是最优的。
备注:
2≤S≤N≤10^5,M=N−1保证答案在 C++ long long 范围内。
题解:很明显就可以得到转移公式dp[x]+=min(dp[v],w);
AC代码:
#include <bits/stdc++.h>
using namespace std;
#define sc(x) scanf("%d",&x)
#define pb push_back
#define ll long long
using namespace std;
const int Max=1e6+5,mod=1e9+7;
const ll INF=1e18;
struct node{
int to;
ll data;
};
vector<node>mp[Max];
ll dp[Max];
void dfs(int fa,int x){
for(int i=0;i<mp[x].size();i++){
int v=mp[x][i].to;
if(fa==v) continue;
dfs(x,v);
dp[x]+=min(dp[v],mp[x][i].data);
}
}
int main(){
int n;sc(n);int m;sc(m);int s;sc(s);
for(int i=0;i<n-1;i++){
int u,v,w;
sc(u);sc(v);sc(w);
mp[u].pb((node){v,w});
mp[v].pb((node){u,w});
}
for(int i=1;i<=n;i++){
if(mp[i].size()==1) dp[i]=INF;
else dp[i]=0;
}
dp[s]=0;
dfs(-1,s);
printf("%lld\n",dp[s]);
}