首页 > 试题广场 >

Rinne Loves Edges

[编程题]Rinne Loves Edges
Rinne  最近了解了如何快速维护可支持插入边删除边的图,并且高效的回答一下奇妙的询问。
她现在拿到了一个 n 个节点 m 条边的无向连通图,每条边有一个边权 w_i
现在她想玩一个游戏:选取一个 “重要点” 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 \leftrightarrow 3是最优的。

备注:
,保证答案在 C++ long long 范围内。

最开始读题,很容易想到用dfs,但是又得保证全局最优解,这时候只用dfs就不行了,需要用dfs加dp,所以这是一道树形dp

我们只需要推出状态转移方程

除了s以外度为1的点,不难想到就是叶节点,我们遍历到叶节点时将叶节点的dp值初始化为INF,因为我们最开始肯定想把连着叶节点的那条边删去,后面再做优化,看有没有总和更小的方法,假设一个情况是,一条主干分了两个叶节点,我们肯定先算出了两个叶节点边切断的边权和,如果这条主干有边权更小的,直接取这个最小值即可

因此状态转移方程为dp[u] += min(dp[v] , w)

接下来只需要写出代码即可:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define debug(x) cerr << #x << ": " << x << '\n';
const int INF = 0x3f3f3f3f3f3f3f3f;
//倒序不要忘记是--不是++
void solve(){
    int n,m,s;cin>>n>>m>>s;
    vector<vector<pair<int,int>>> e(n+1);
    for(int i=1;i<=m;i++){
        int u,v,w;cin>>u>>v>>w;
        e[u].push_back({v,w});
        e[v].push_back({u,w});
    }
    vector<int> dp(n+1);
    auto dfs=[&](auto dfs,int u,int fa)->void{
        if(u!=s&&e[u].size()==1) dp[u]=INF;
        // debug(u);
        for(auto i:e[u]){
            auto [v,w]=i;
            if(v==fa) continue;
            dfs(dfs,v,u);
            dp[u]+=min(dp[v],w);
        }
    };
    dfs(dfs,s,0);
    cout<<dp[s];
}
signed main(){
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int t = 1;
    // cin>>t;
    while(t--){
        solve();
    }return 0;
}

发表于 今天 10:54:38 回复(0)