• CSU 1126 DFS前缀和


    在一棵树上找影响最小的某个点,某个点的影响是等于其他点到他的距离*其他点的权值 的和

    我一开始也找不到什么好的方法,只能想到每个点暴力去判断,但是这样肯定会超时(10^5个点),又有点想用类似前缀和,但是这是在树上,不是很好搞

    不过最后还是得用到前缀和,先dfs1把从0号节点出发的整个值算出来,并且沿途记录权值前缀和。之后再用一个dfs2从0号节点开始转移,因为有之前预处理的前缀和以及总和,每次转移只要O(1)复杂度就可以算出来。整个两次dfs都仅仅对每个点搜索了一遍,不会超时

    代码不是我写的 用来参考

    #include <iostream>
    #include <vector>
    using namespace std;
      
    int N;
    long long cost[1<<17], cows[1<<17], down[1<<17], up[1<<17];
    vector<vector<long long> > e, w;
      
    long long dfs1(int cur, int prev) {
      down[cur] = cows[cur];
      long long c = 0;
      for(int i = 0; i < e[cur].size(); i++) {
        if(e[cur][i] == prev) continue;
        c += dfs1(e[cur][i], cur);
        c += down[e[cur][i]]*w[cur][i];
        down[cur] += down[e[cur][i]];
      }
      return c;
    }
      
    long long dfs2(int cur, int prev) {
      long long c = cost[cur];
      for(int i = 0; i < e[cur].size(); i++) {
        if(e[cur][i] == prev) continue;
        cost[e[cur][i]] = cost[cur]-down[e[cur][i]]*w[cur][i]+up[e[cur][i]]*w[cur][i];
        c = min(c, dfs2(e[cur][i], cur));
      }
      return c;
    }
      
    int main() {
      //FILE* in = fopen("red.in", "r");
      //FILE* out = fopen("red.out", "w");
      
      scanf("%d", &N);
      e.resize(N); w.resize(N);
      for(int i = 0; i < N; i++) scanf("%lld", &cows[i]);
      for(int i = 0; i < N-1; i++) {
        long long a, b, c;
        scanf("%lld %lld %lld", &a, &b, &c);
        a--; b--;
        e[a].push_back(b); w[a].push_back(c);
        e[b].push_back(a); w[b].push_back(c);
      }
      
      cost[0] = dfs1(0, -1);
      for(int i = 0; i < N; i++) up[i] = down[0] - down[i];
      printf("%lld
    ", dfs2(0, -1));
      
      //fclose(in);
      //fclose(out);
    }
  • 相关阅读:
    C语言 · 最大最小值
    C语言 · 三个整数的排序
    C语言 · 简单加法
    C语言 · FJ的字符串
    C语言 · 分解质因数
    C语言 · 数的统计
    C语言 · 成绩的等级输出
    C语言 · 区间K大数查询
    shell学习目录
    数据库学习目录
  • 原文地址:https://www.cnblogs.com/kkrisen/p/3877296.html
Copyright © 2020-2023  润新知