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

《P2700 逐个击破》

题目背景

三大战役的平津战场上,傅作义集团在以北平、天津为中心,东起唐山西至张家口的铁路线上摆起了一字长蛇阵,并企图在溃败时从海上南逃或向西逃窜。为了就地歼敌不让其逃走,指挥官制定了先切断敌人东西两头退路然后再逐个歼灭敌人的战略方针。秉承伟大军事家的战略思想,作为一个有智慧的军长你,遇到了一个类似的战场局面。

题目描述

现在有 N 个城市,其中 K 个被敌方军团占领了,N 个城市间有 N−1 条公路相连,破坏其中某条公路的代价是已知的,现在,告诉你 K 个敌方军团所在的城市,以及所有公路破坏的代价,请你算出花费最少的代价将这 K 个地方军团互相隔离开,以便第二步逐个击破敌人。

输入格式

第一行包含两个正整数 N 和 K。

第二行包含 K 个整数,表示哪个城市被敌军占领。

接下来 N−1 行,每行包含三个正整数 a,b,c,表示从 a 城市到 b 城市有一条公路,以及破坏的代价 c。城市的编号从 0 开始。

输出格式

输出一行一个整数,表示最少花费的代价。

输入输出样例

输入 #1复制

5 3
1 2 4
1 0 4
1 3 8
2 1 1
2 4 3

输出 #1复制

4

说明/提示

对于 10% 的数据,N≤10。

对于 100% 的数据,2≤N≤105,2≤K≤N,1≤c≤106。

代码实现:

#include<cstdio>
#include<algorithm>
#define MAX_NODE 100001
#define MAX_EDGE 200001
#define Loop(var, start, end) for(int var = start; var <= end; ++var)
using namespace std;
typedef long long LongLong;

// 图的相关变量
int edgeCount;                // 边的数量计数器
int headNode[MAX_NODE];       // 每个节点的边链表头
int targetNode[MAX_EDGE];     // 边指向的目标节点
int nextEdge[MAX_EDGE];       // 下一条边的索引
int edgeWeight[MAX_EDGE];     // 边的权重

// 添加边的函数
inline void addEdge(int fromNode, int toNode, int weight) {
targetNode[++edgeCount] = toNode;
nextEdge[edgeCount] = headNode[fromNode];
headNode[fromNode] = edgeCount;
edgeWeight[edgeCount] = weight;
}

LongLong result;              // 最终结果
bool isSpecialNode[MAX_NODE]; // 标记是否为特殊节点

// 深度优先搜索函数
// 返回值:子树中能保留的最大最小边权重
inline int dfs(int currentNode, int parentNode) {
LongLong totalSum = 0;    // 子树中所有有效边的总和
LongLong maxEdge = 0;     // 子树中最大的有效边
LongLong currentEdge;     // 当前边的权重(取最小值)

// 遍历当前节点的所有边
for(int edgeIndex = headNode[currentNode]; edgeIndex; edgeIndex = nextEdge[edgeIndex]) {
int neighborNode = targetNode[edgeIndex];
if(neighborNode == parentNode) continue;

// 递归计算子树,取返回值和当前边权重的最小值
currentEdge = min((LongLong)dfs(neighborNode, currentNode), (LongLong)edgeWeight[edgeIndex]);
totalSum += currentEdge;
maxEdge = max(maxEdge, currentEdge);  // 更新最大边
}

result += totalSum;

// 如果是特殊节点,返回一个很大的值表示这条路径需要保留
if(isSpecialNode[currentNode]) return 1e9;

// 非特殊节点,减去最大边并返回该值
result -= maxEdge;
return maxEdge;
}

int main() {
#ifndef ONLINE_JUDGE
freopen("pro.in", "r", stdin);
freopen("pro.out", "w", stdout);
#endif

int nodeCount, specialCount;
scanf("%d%d", &nodeCount, &specialCount);

// 标记特殊节点
Loop(i, 1, specialCount) {
int node;
scanf("%d", &node);
isSpecialNode[node] = true;
}

// 读取并添加所有边
Loop(i, 1, nodeCount - 1) {
int u, v, weight;
scanf("%d%d%d", &u, &v, &weight);
addEdge(u, v, weight);
addEdge(v, u, weight);
}

// 从节点0开始深度优先搜索
dfs(0, -1);

// 输出结果
printf("%lld", result);
return 0;
}

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

相关文章:

  • Design Compiler:逻辑库名与逻辑库文件名及其指定方式
  • 自学嵌入式第二十四天:数据结构(4)-栈
  • JetBrains Mono字体
  • Django ModelForm
  • 用 Python 写的自动化测试 WPF 程序的一个案例
  • Jmeter接口测试之文件上传
  • XXL-Job REST API 工具类完全解析:简化分布式任务调度集成
  • WebSocket和跨域问题
  • Android为ijkplayer设置音频发音类型usage
  • 如何用 SolveigMM Video Splitter 从视频中提取 AAC 音频
  • CMake3: CMake的嵌套使用与自定义库
  • Spring Event 企业级应用
  • 笔试——Day45
  • Prompt魔法:提示词工程与ChatGPT行业应用读书笔记:提示词设计全能指南
  • 第四章:大模型(LLM)】07.Prompt工程-(7)角色提示
  • Flink基础
  • 解锁工业级Prompt设计,打造高准确率AI应用
  • Web自动化测试:测试用例流程设计
  • Java设计模式-解释器模式
  • 策略模式 vs 适配器模式
  • 基于STM32设计的大棚育苗管理系统(4G+华为云IOT)_265
  • 移动应用抓包与调试实战 Charles工具在iOS和Android中的应用
  • 数据结构初阶:详解二叉树(三):链式二叉树
  • system\core\init\init.cpp----LoadBootScripts()解析init.rc(1)
  • STM32之串口详解
  • 学习Linux嵌入式(正点原子imx课程)开发到底是在学什么
  • Spring Cloud Netflix学习笔记06-Zuul
  • Kafka消息持久化机制全解析:存储原理与实战场景
  • Kafka集成Flume
  • 人工智能 -- 循环神经网络day1 -- 自然语言基础、NLP基础概率、NLP基本流程、NLP特征工程、NLP特征输入