当前位置: 首页 > news >正文

《P2052 [NOI2011] 道路修建》

题目描述

在 W 星球上有 n 个国家。为了各自国家的经济发展,他们决定在各个国家之间建设双向道路使得国家之间连通。但是每个国家的国王都很吝啬,他们只愿意修建恰好 n−1 条双向道路。

每条道路的修建都要付出一定的费用,这个费用等于道路长度乘以道路两端 的国家个数之差的绝对值。例如,在下图中,虚线所示道路两端分别有 2 个、4 个国家,如果该道路长度为 1,则费用为 1×∣2−4∣=2。图中圆圈里的数字表示国家的编号。

由于国家的数量十分庞大,道路的建造方案有很多种,同时每种方案的修建费用难以用人工计算,国王们决定找人设计一个软件,对于给定的建造方案,计算出所需要的费用。请你帮助国王们设计一个这样的软件。

输入格式

输入的第一行包含一个整数 n,表示 W 星球上的国家的数量,国家从 1 到 n 编号。

接下来 n−1 行描述道路建设情况,其中第 i 行包含三个整数 ai​,bi​ 和 ci​,表示第 i 条双向道路修建在 ai​ 与 bi​ 两个国家之间,长度为 ci​。

输出格式

输出一个整数,表示修建所有道路所需要的总费用。

输入输出样例

输入 #1复制

6
1 2 1
1 3 1
1 4 2
6 3 1
5 2 1

输出 #1复制

20

说明/提示

对于 100% 的数据,1≤ai​,bi​≤n,0≤ci​≤106,2≤n≤106。

测试点编号n=
12
210
3100
4200
5500
6600
7800
81000
9104
102×104
115×104
126×104
138×104
14105
156×105
167×105
178×105
189×105
19,20

106

代码实现:

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

typedef long long ll;

struct Edge {
int a, b, c;
};

vector<vector<pair<int, int > > > adj;  // 邻接表:adj[u]存储(u的邻接点, 边的长度)
vector<int> size_arr;               // 存储每个节点为根的子树大小
vector<int> parent;                 // 存储每个节点的父节点
vector<bool> visited;               // 标记节点是否已访问

// 深度优先搜索计算子树大小
void dfs(int u) {
visited[u] = true;
size_arr[u] = 1;  // 子树大小初始化为1(包含自身)

// 遍历u的所有邻接点(使用下标访问)
for (int i = 0; i < adj[u].size(); ++i) {
// 获取邻接点v和对应的边长度(这里边长度暂时用不到)
int v = adj[u][i].first;
// int c = adj[u][i].second;  // 暂时不需要

// 如果v不是父节点且未访问过,说明是子节点
if (!visited[v] && v != parent[u]) {
parent[v] = u;  // 记录父节点
dfs(v);         // 递归计算子树大小
size_arr[u] += size_arr[v];  // 累加子树大小
}
}
}

int main() {
ios::sync_with_stdio(false);
cin.tie(0);

    int n;
cin >> n;

    // 初始化容器大小
adj.resize(n + 1);
size_arr.resize(n + 1, 0);
parent.resize(n + 1, -1);
visited.resize(n + 1, false);
vector<Edge> edge_list(n - 1);  // 存储所有边的信息

    // 读取边信息并构建邻接表
for (int i = 0; i < n - 1; ++i) {
int a, b, c;
cin >> a >> b >> c;
// 向邻接表中添加双向边(用make_pair构造pair)
adj[a].push_back(make_pair(b, c));
adj[b].push_back(make_pair(a, c));
// 保存边的信息
edge_list[i].a = a;
edge_list[i].b = b;
edge_list[i].c = c;
}

    // 从节点1开始DFS(任意节点均可作为根,这里选1)
dfs(1);

    // 计算总费用
ll total = 0;
for (int i = 0; i < n - 1; ++i) {
int a = edge_list[i].a;
int b = edge_list[i].b;
int c = edge_list[i].c;

        // 确定子节点(边的一端是另一端的父节点)
int child;
if (parent[b] == a) {
child = b;  // a是b的父节点,子树为b
} else {
child = a;  // b是a的父节点,子树为a
}

        // 子树大小为size_arr[child],另一端子树大小为n - size_arr[child]
int s = size_arr[child];
int k1= 2*s - n;
total += (ll)c * abs(k1);  // 费用 = 长度 * |2s - n|
}

    cout << total << endl;

    return 0;
}

http://www.dtcms.com/a/276476.html

相关文章:

  • JavaScript:移动端特效--从触屏事件到本地存储
  • (LeetCode 面试经典 150 题 )3. 无重复字符的最长子串 (哈希表+双指针)
  • 两数之和 https://leetcode.cn/problems/two-sum/description/
  • 基于hugo的静态博客站点部署
  • 苹果公司高ROE分析
  • Druid 连接池使用详解
  • 基于 SpringBoot+Uniapp 易丢丢失物招领微信小程序系统设计与实现
  • BugBug.io 使用全流程(202507)
  • Kubernetes持久卷实战
  • zcbus使用数据抽取相当数据量实况
  • 8. JVM类装载的执行过程
  • hive的索引
  • DBeaver连接MySQL8.0报错Public Key Retrieval is not allowed
  • C语言基础知识--位段
  • UE制作的 AI 交互数字人嵌入到 Vue 开发的信息系统中的方法和步骤
  • 【MaterialDesign】谷歌Material(Google Material Icons) 图标英文 对照一览表
  • AI问答:成为合格产品经理所需能力的综合总结
  • dify工作流1:快速上手ai应用
  • 计算机毕业设计Java停车场管理系统 基于Java的智能停车场管理系统开发 Java语言实现的停车场综合管理平台
  • 网络通信模型对比:OSI与TCP/IP参考模型解析
  • 《Java Web程序设计》实验报告三 使用DIV+CSS制作网站首页
  • ServiceNow Portal前端页面实战讲解
  • [案例八] NX二次开发长圆孔的实现(支持实体)
  • C++中Lambda表达式 [ ] 的写法
  • Redis面试精讲 Day 1:Redis核心特性与应用场景
  • 浅谈 Python 中的 yield——生成器对象与函数调用的区别
  • 2025必问46道软件测试面试题(答案+文档)
  • Armstrong 公理系统深度解析
  • 网络安全初级第一次作业
  • super task 事件驱动框架