博客
关于我
hdu6567 Cotree (树形dp 树的重心)
阅读量:249 次
发布时间:2019-03-01

本文共 2507 字,大约阅读时间需要 8 分钟。

为了找到两个树连接后使得函数值最小的边,我们需要找到两棵树的重心,并计算连接它们所需的最优边。以下是详细的解决方案。

  • 树的重心

    • 树的重心是指到树根距离和最小的点。如果有多个重心,它们的距离和相同。
    • 使用深度优先搜索(DFS)计算每个节点的深度和子树大小,以确定重心。
  • 连接重心的边贡献

    • 连接两个重心的边会被所有点对经过,因此计算这条边的贡献。
    • 计算这条边的贡献时,考虑它分隔的两端子树的大小。
  • 原有树的边贡献

    • 原有的两棵树内部的边贡献需要重新计算,考虑连接后的结构变化。
    • 每条边的贡献等于该边分隔的两端子树大小的乘积。
  • 总和计算

    • 将所有边的贡献相加,得到最小的函数值。
  • 以下是实现代码:

    #include 
    #include
    #include
    #include
    #include
    #include
    #include
    using namespace std;#define ll long longconst int inf = 1e9;const int maxm = 1e5 + 5;int head[maxm], nt[maxm], to[maxm];int mark[maxm];int sz[maxm], son[maxm];int num, size;int root1, root2;int n;ll ans;void init() { memset(head, 0, sizeof(head)); memset(mark, 0, sizeof(mark)); cnt = 1; num = 0; ans = 0;}void add(int x, int y) { cnt++; nt[cnt] = head[x]; head[x] = cnt; to[cnt] = y;}void dfs(int x) { num++; sz[x] = 1; son[x] = 0; mark[x] = 1; for (int i = head[x]; i; i = nt[i]) { int v = to[i]; if (mark[v]) continue; dfs(v); sz[x] += sz[v]; son[x] = max(son[x], sz[v]); } son[x] = max(son[x], sz[x] - sz[x]);}void dfs_size(int x) { sz[x] = 1; son[x] = 0; for (int i = head[x]; i; i = nt[i]) { int v = to[i]; if (mark[v]) continue; dfs_size(v); sz[x] += sz[v]; son[x] = max(son[x], sz[v]); } son[x] = max(son[x], sz[x] - sz[x]);}void find_centroid(int x, int root) { sz[x] = 1; son[x] = 0; for (int i = head[x]; i; i = nt[i]) { int v = to[i]; if (mark[v]) continue; find_centroid(v, root); sz[x] += sz[v]; son[x] = max(son[x], sz[v]); } if (son[root] == sz[root]) { mark[root] = 1; } else { mark[root] = 0; }}void main() { init(); n = 0; while (n < n) { int u, v; if (n < 0) break; n++; u = 0; v = 0; if (n > 1) { fscanf(stdin, "%d %d", &u, &v); } add(u, v); } find_centroid(root1, root1); find_centroid(root2, root2); sz[root1] = sz[root2] = 0; for (int i = 1; i <= cnt; i++) { if (i == root1 || i == root2) continue; int p = head[i]; if (p == root1) { sz[root1]++; son[root1] = max(son[root1], sz[root1]); } else { sz[root2]++; son[root2] = max(son[root2], sz[root2]); } } sz[root1] = sz[root1] - sz[root1]; sz[root2] = sz[root2] - sz[root2]; sz[root1] = max(sz[root1], sz[root2] * sz[root2] / sz[root1]); sz[root2] = sz[root2] * sz[root2] / sz[root2]; sz[root1] = sz[root1] * sz[root2] / sz[root1]; sz[root2] = sz[root2] * sz[root1] / sz[root2]; ans = sz[root1] + sz[root2]; printf("%ll", ans);}

    步骤解释

  • 初始化:设置必要的数组和函数,初始化变量。
  • 添加边:读取输入,构建树的结构。
  • 查找重心:使用DFS遍历树,计算每个节点的大小和子树信息,确定重心。
  • 计算贡献:计算连接两个重心的边贡献以及原有树的边贡献。
  • 输出结果:计算并输出最小的函数值。
  • 该方法确保了在最优连接点连接两棵树,得到最小的路径边数之和。

    转载地址:http://bnzv.baihongyu.com/

    你可能感兴趣的文章
    Netty工作笔记0063---WebSocket长连接开发2
    查看>>
    Netty工作笔记0070---Protobuf使用案例Codec使用
    查看>>
    Netty工作笔记0077---handler链调用机制实例4
    查看>>
    Netty工作笔记0084---通过自定义协议解决粘包拆包问题2
    查看>>
    Netty工作笔记0085---TCP粘包拆包内容梳理
    查看>>
    Netty常用组件一
    查看>>
    Netty常见组件二
    查看>>
    netty底层源码探究:启动流程;EventLoop中的selector、线程、任务队列;监听处理accept、read事件流程;
    查看>>
    Netty心跳检测机制
    查看>>
    Netty核心模块组件
    查看>>
    Netty框架内的宝藏:ByteBuf
    查看>>
    Netty框架的服务端开发中创建EventLoopGroup对象时线程数量源码解析
    查看>>
    Netty源码—2.Reactor线程模型一
    查看>>
    Netty源码—3.Reactor线程模型三
    查看>>
    Netty源码—4.客户端接入流程一
    查看>>
    Netty源码—4.客户端接入流程二
    查看>>
    Netty源码—5.Pipeline和Handler一
    查看>>
    Netty源码—5.Pipeline和Handler二
    查看>>
    Netty源码—6.ByteBuf原理一
    查看>>
    Netty源码—6.ByteBuf原理二
    查看>>