此题目的意思就是现在有以s节点为根节点的一棵树,要求断掉一些边, 使得叶子节点无法到达根节点(在
一个树中, 只有一个度的节点只有叶子节点,或者单链式的树(如样例2))
单链式的树根节点和叶子节点都有且只有一个度,所以要特殊考虑一下
下面直接考虑树形dp做法
考虑一下研究总问题:以s为节点的子树断掉一些边,使得叶子节点无法到达根节点
那么在dp做法下, 肯定要考虑子问题 , 那么总问题的子问题肯定和它的孩子节点有关
用dp[u] 表示以u为节点的子树断掉一些边, 使得叶子节点无法到达u节点
通常做法就是考虑s节点的孩子节点 , 对于s节点来说
1、直接断掉一条到孩子节点v的边 , 那么这个时候这个v这个孩子就不用考虑了(因为这个子树所有点都不能到达s节点了)
2、不断掉到孩子节点的v的边, 那么我就要考虑问题:
以v为节点的子树断掉一些边, 使得叶子节点无法到达v节点
第二个情况实际上也就是总问题的子问题
什么时候选择第一种情况 :
如果只考虑s节点,那么dp[s] = ??
对于s节点的孩子节点x 来说, 如果第一种情况比第二种情况优 , 也就是dis(s , x) > dp[x]
那么就选择第一种情况 , 否则的就选择第二种情况
那么用dp的思想也就是当前节点u的孩子节点的贡献就是 min(dp[v] , dis(u , v))
还因为u节点不止一个孩子节点, 那么就是dp[u] += min(dp[v] , dis(u , v))
所谓的记忆化搜索(蒟蒻个人感觉来说) 就是搜索过的东西,也就是搜索过的答案全部记录对应的位置 , 如果搜索到了 已经被搜过的点 ,那么就直接返回 , 否则的话,完成当前搜索步骤,在return的时候,同时记录相应的答案
树形dp一般都是先对于当前节点直接搜索, 然后在按照dp[u] += min(dis(u , v) , dp[v]) 计算贡献 , 因为他要从当前节点搜到叶子节点, 然后返回的时候在将贡献计算
我才接触dp没多久
树形dp
#include <bits/stdc++.h>
using namespace std ;
const int N = 1e5 + 10 ;
typedef long long ll ;
vector<pair<int , ll>> v[N] ;
int n , m , s ;
ll dp[N] ;
void dfs(int u , int fa)
{
if(v[u].size() == 1 && u != s )
{
dp[u] = 0x3f3f3f3f ;
// 这个要特殊处理, 因为单链式的叶子节点和根节点都有1个度
// 因为这个节点肯定是叶子节点 , 然后呢返回上一层就是它的父亲节点
// dp[fa] += min(dp[u] , dis(u , fa)) ,
// 这个时候也就是边界, 肯定是选择dis(u , fa) ,
//将孩子节点直接断掉, 不考虑dp[u] ,所以将dp[u] 设置为正无穷
return ;
}
for(auto x : v[u])
{
ll j = x.first , w = x.second ;
if(j == fa) continue ;
dfs(j , u) ;
dp[u] += min(dp[j] , w) ;
}
}
int main()
{
cin >> n >> m >> s ;
for(int i = 1; i <= m ;i ++)
{
int a , b , c ;
cin >> a >> b>> c ;
v[a].push_back({b , c}) ;
v[b].push_back({a , c}) ;
}
dfs(s , 0) ;
cout << dp[s] << endl ;
return 0;
}记忆化搜索 + 树形dp
#include <bits/stdc++.h>
using namespace std ;
const int N = 1e5 + 10 ;
typedef long long ll ;
vector<pair<int , ll>> v[N] ;
int n , m , s ;
ll dp[N] ;
const ll INF = 1e18 ;
ll dfs(int u , int fa)
{
if(dp[u]) return dp[u] ;
if(v[u].size() == 1 && u != s) return INF ;
ll ans = 0 ;
for(auto x : v[u])
{
ll a = x.first , w = x.second ;
if(a == fa) continue ;
ans += min(dfs(a , u) , w) ;
}
return dp[u] = ans ;
}
int main()
{
cin >> n >> m >> s ;
for(int i = 1; i <= m ;i ++)
{
int a , b , c ;
cin >> a >> b>> c ;
v[a].push_back({b , c}) ;
v[b].push_back({a , c}) ;
}
cout << dfs(s , 0) << endl ;
return 0;
}
京公网安备 11010502036488号