其他分享
首页 > 其他分享> > CF219D Choosing Capital for Treeland(换根DP)题解

CF219D Choosing Capital for Treeland(换根DP)题解

作者:互联网

思路

首先,我们根据题意建树,并给边附上权值:原有的边权值为\(0\),反向边权值为\(1\),代表走这条边所需代价。

第一次\(DFS\),钦定\(1\)为根,我们可以求出以\(1\)为根的答案。

第二次\(DFS\),考虑根由\(u\)转移到\(v\)时答案会怎么变。

设\(f_u\)为以\(u\)为根时的最小转换次数,则有:

\[f_v=f_u - (val_{u->v}==1) + (val_{u -> v} == 0) \quad [v \in ch_u] \]

其中,\(val_{u->v}\)表示由\(u\)连向\(v\)的边的权值。

这样,我们就可以方便地统计出答案了!

参考代码

#include <cstdio>
#include <algorithm>

using namespace std;

const int maxn = 2e5 + 10;
int n,head[maxn << 1],num;
struct Edge{
    int then,to,val;
}e[maxn << 1];

void add(int u, int v, int val){e[++num] = (Edge){head[u], v, val}; head[u] = num;}

int f[maxn];
void DFS1(int u, int fa){
    for(int i = head[u]; i; i = e[i].then){
        int v = e[i].to;
        if(v != fa){
            f[u] += e[i].val;
            DFS1(v, u);
            f[u] += f[v];
        }
    }
}

void DFS2(int u, int fa){
    for(int i = head[u]; i; i = e[i].then){
        int v = e[i].to;
        if(v != fa){
            f[v] = f[u] + (e[i].val == 0) - (e[i].val == 1);
            DFS2(v, u);
        }
    }
}

int main(){
    scanf("%d", &n);
    for(int i = 1; i < n; ++ i){
        int u,v; scanf("%d%d", &u, &v);
        add(u, v, 0); add(v, u, 1);
    }
    DFS1(1, 1); DFS2(1, 1);
    int Ans = 0x3f3f3f3f;
    for(int i = 1; i <= n; ++ i) Ans = min(Ans, f[i]);
    printf("%d\n", Ans);
    for(int i = 1; i <= n; ++ i)
        if(f[i] == Ans) printf("%d ", i);
    printf("\n");
    return 0;
}

标签:val,Treeland,int,题解,边权,maxn,CF219D,权值,为根
来源: https://www.cnblogs.com/whenc/p/13967585.html