zoukankan      html  css  js  c++  java
  • CF219D Choosing Capital for Treeland(换根DP)题解

    思路

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

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

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

    • (u)(v)的边权为(0),那么一开始我们是从(u)(v),没有计算边权,所以不仅要加上从(v)(u)的边权(1),还要把一开始没算的边权加上,总共要(+2)
    • 边权为(1)同理,不过是(-2)

    (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
    ", Ans);
        for(int i = 1; i <= n; ++ i)
            if(f[i] == Ans) printf("%d ", i);
        printf("
    ");
        return 0;
    }
    
  • 相关阅读:
    map & reduce
    Generator
    切片
    函数参数
    Dict & Set
    list,tuple
    selenium鼠标和键盘操作
    selenium元素定位以及点击事件
    css定位
    xpath
  • 原文地址:https://www.cnblogs.com/whenc/p/13967585.html
Copyright © 2011-2022 走看看