换根dp
什么是换根dp,如果已知以某一个点为根节点的树的总深度之和,如何求以其它节点为根的总深度之和。
换根dp可以用于求解有n个节点的树,以编号1-n为根节点的树的总深度之和的最小值或最大值。
如何求呢?
- 首先先求出以1为根节点的树的总深度size和每个节点的深度h,这个可以一遍dfs求出。
void dfs1(int s,int f)
{
int l = a[s].size();
for(int i = 0; i < l; i++){
int v = a[s][i];
if(v == f) continue;
h[v] = h[s] + 1;
ans += h[v];
dfs1(v,s);
size[s] += size[v];
}
size[s] += 1;
}
- 然后定义dp[s]表示以s为节点的深度和。假设v是u的孩子节点,那么dp[v] = dp[u] + n - 2*size[v],因为孩子节点v的子树上的节点到v的深度为到节点u的深度减一,其它节点深度加一,我们已知节点v的子树的小为size[v],每个节点深度减一,总共size[v]个节点,所以减去size[v],剩余其它节点为n-size[i],所以dp[v] = dp[v] - size[v]+n-size[v] = dp[u] + n - 2*size[v].再一遍dfs求。
void dfs2(int s,int f)
{
ans = min(ans,dp[s]);
int l = a[s].size();
for(int i = 0; i < l; i++){
int v = a[s][i];
if(v == f) continue;
dp[v] = dp[s] + n - 2*size[v];
dfs2(v,s);
// ans = min(ans,)
}
}
附上例题:https://ac.nowcoder.com/acm/contest/4479/C
Problem
求以1-n为根节点的总深度最小值。
Solution
利用换根dp,思路见上面解释。
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#include <list>
#define ull unsigned long long
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int N = 500005;
const ll ds = 1e15+7;
const double p1 = 3.141592653589793238462643383;
const ll res = 233;
using namespace std;
vector<int>a[1000005];
int size[1000005],h[1000005],n,u,v;
ll dp[1000005],ans = 0;
void dfs1(int s,int f)
{
int l = a[s].size();
for(int i = 0; i < l; i++){
int v = a[s][i];
if(v == f) continue;
h[v] = h[s] + 1;
ans += h[v];
dfs1(v,s);
size[s] += size[v];
}
size[s] += 1;
}
void dfs2(int s,int f)
{
ans = min(ans,dp[s]);
int l = a[s].size();
for(int i = 0; i < l; i++){
int v = a[s][i];
if(v == f) continue;
dp[v] = dp[s] + n - 2*size[v];
dfs2(v,s);
// ans = min(ans,)
}
}
int main()
{
cin >> n;
for(int i = 1; i < n; i++){
cin >> u >> v;
a[u].push_back(v);
a[v].push_back(u);
}
dfs1(1,-1);
//cout << ans << endl;
dp[1] = ans;
dfs2(1,-1);
cout << ans << endl;
// for(int i = 1; i <= n; i++){
// cout << h[i] << " ";
// }
return 0;
}