洛谷刷题日记12||图的遍历

反向建边 + dfs

按题目来每次考虑每个点可以到达点编号最大的点,不如考虑较大的点可以反向到达哪些点

循环从N到1,则每个点i能访问到的结点的A值都是i

每个点访问一次,这个A值就是最优的,因为之后如果再访问到这个结点那么答案肯定没当前大了

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;#define MAXL 100010 // 最大节点数int N, M; // 节点数和边数
int A[MAXL]; // 结果数组,A[x] 表示从节点 x 出发能到达的编号最大的点
vector<int> G[MAXL]; // 邻接表,用于存储图// 深度优先搜索函数
void dfs(int x, int d) {if (A[x]) return; // 如果节点 x 已经访问过,直接返回A[x] = d; // 更新节点 x 的结果为 d,表示从 d 出发可以到达 xfor (int i = 0; i < G[x].size(); i++) { // 遍历节点 x 的所有邻接点  反向dfs(G[x][i], d); // 递归处理邻接点}
}int main() {int u, v; // 边的两个端点scanf("%d%d", &N, &M); // 输入节点数 N 和边数 M// 读入边并构建反向图for (int i = 1; i <= M; i++) {scanf("%d%d", &u, &v); // 输入边 (u, v)G[v].push_back(u); // 反向建边,将 v 指向 u}// 从编号最大的节点依次进行 DFSfor (int i = N; i > 0; i--) {dfs(i, i); // 从节点 i 出发,更新所有能到达的节点}// 输出结果for (int i = 1; i <= N; i++) {printf("%d ", A[i]); // 输出从 1 到 N 的结果}printf("\n"); // 换行return 0;
}



 这是一个经典的 拓扑排序 + 动态规划 问题。可以将每个杂务视为一个节点,准备工作视为有向边,然后通过拓扑排序确定每个节点的完成顺序,最后使用动态规划求出完成所有工作的最短时间。以下是用 C++ 实现该问题的完整代码。

 

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>using namespace std;// 定义最大节点数
const int MAXN = 10000;vector<int> adj[MAXN + 1]; // 邻接表存储依赖关系,adj[i] 表示 i 的所有后继任务
int in_degree[MAXN + 1];   // 每个节点的入度,表示还有多少依赖任务未完成
int time_needed[MAXN + 1]; // 每个任务所需的完成时间
int dp[MAXN + 1];          // dp[i] 表示完成到第 i 个任务的最短时间int main() {int n;cin >> n; // 输入任务数// 输入每个任务的信息for (int i = 1; i <= n; ++i) {int task, time, dep;cin >> task >> time; // 任务编号和所需时间time_needed[task] = time; // 保存任务所需时间// 输入当前任务的所有依赖任务while (cin >> dep && dep != 0) {adj[dep].push_back(task); // 从依赖任务到当前任务的有向边++in_degree[task]; // 当前任务的入度加 1}}// 使用队列进行拓扑排序queue<int> q;for (int i = 1; i <= n; ++i) {// 将所有入度为 0 的任务加入队列(可以直接开始的任务)if (in_degree[i] == 0) {q.push(i);dp[i] = time_needed[i]; // 初始任务的最短时间就是自身所需时间}}// 拓扑排序处理任务while (!q.empty()) {int cur = q.front(); // 当前处理的任务q.pop();// 遍历当前任务的所有后继任务for (int next : adj[cur]) {// 更新后继任务的最短完成时间dp[next] = max(dp[next], dp[cur] + time_needed[next]);// 将后继任务的入度减 1if (--in_degree[next] == 0) {// 如果后继任务的入度变为 0,加入队列q.push(next);}}}// 最后计算所有任务的最短完成时间int result = 0;for (int i = 1; i <= n; ++i) {result = max(result, dp[i]); // 找到最大的 dp 值}cout << result << endl; // 输出结果return 0;
}

关键逻辑详解

  1. 任务依赖建图

    • 使用邻接表 adj 存储任务的依赖关系,每个任务指向它的后续任务。
    • 入度数组 in_degree 记录每个任务的依赖任务数。
  2. 拓扑排序

    • 使用队列处理入度为 0 的任务,表示当前可以直接完成的任务。
    • 完成一个任务后,将其后续任务的入度减 1;如果后续任务的入度变为 0,则加入队列。
  3. 动态规划更新最短完成时间

    • dp[i] 表示完成任务 i 的最短时间。
    • 更新公式:dp[next] = max(dp[next], dp[cur] + time_needed[next]),即后续任务的完成时间至少是当前任务完成时间加上后续任务所需时间。
  4. 结果计算

    • 最后取所有 dp[i] 的最大值,表示完成所有任务的最短时间。

 样例输入

7
1 5 0
2 2 1 0
3 3 2 0
4 6 1 0
5 1 2 4 0
6 8 2 4 0
7 4 3 5 6 0

 

算法逻辑

第 1 步:初始化队列

将入度为 0 的任务加入队列(这些任务可以直接开始完成):

初始队列:[1]
初始 dp:dp[1] = 5 (任务 1 自身时间)


第 2 步:拓扑排序和动态规划更新

依次从队列中取出任务,更新其后续任务的完成时间。

处理过程:

  1. 取出任务 1

    • 后续任务:2, 4
    • 更新后续任务的 dp:
      • dp[2] = max(dp[2], dp[1] + time_needed[2]) = 5 + 2 = 7
      • dp[4] = max(dp[4], dp[1] + time_needed[4]) = 5 + 6 = 11
    • 入度更新:
      • in_degree[2] = 0 → 加入队列
      • in_degree[4] = 0 → 加入队列

    队列:[2, 4]

  2. 取出任务 2

    • 后续任务:3, 5, 6
    • 更新后续任务的 dp:
      • dp[3] = max(dp[3], dp[2] + time_needed[3]) = 7 + 3 = 10
      • dp[5] = max(dp[5], dp[2] + time_needed[5]) = 7 + 1 = 8
      • dp[6] = max(dp[6], dp[2] + time_needed[6]) = 7 + 8 = 15
    • 入度更新:
      • in_degree[3] = 0 → 加入队列
      • in_degree[5] = 1
      • in_degree[6] = 1

    队列:[4, 3]

  3. 取出任务 4

    • 后续任务:5, 6
    • 更新后续任务的 dp:
      • dp[5] = max(dp[5], dp[4] + time_needed[5]) = 11 + 1 = 12
      • dp[6] = max(dp[6], dp[4] + time_needed[6]) = 11 + 8 = 19
    • 入度更新:
      • in_degree[5] = 0 → 加入队列
      • in_degree[6] = 0 → 加入队列

    队列:[3, 5, 6]

  4. 后面的类似




 

解题思路

  1. 反向建图:将所有有向边反向,变成从目标节点指向源节点的边。这样可以方便地从每个奶牛所在的牧场出发,找到所有可以到达的节点。

  2. 多源 BFS:对于每头奶牛所在的牧场,利用 BFS 或 DFS 遍历所有可到达的节点,同时记录每个节点被多少头奶牛访问过。

  3. 统计结果:如果某个节点被所有奶牛访问过(即计数等于奶牛数量 K),则该节点为可行的聚集地点。

 

#include <iostream>
#include <vector>
#include <queue>
#include <cstring>using namespace std;const int MAXN = 1000; // 最大牧场数
const int MAXK = 100;  // 最大奶牛数// 反向图的邻接表
vector<int> reverse_graph[MAXN + 1];
// 每个牧场被访问的奶牛数量
int visit_count[MAXN + 1];// 使用 BFS 遍历从某个起始点可以到达的所有节点
void bfs(int start) {// 记录当前奶牛访问时是否已经到达某节点bool visited[MAXN + 1] = {false};queue<int> q;// 初始化 BFS 队列q.push(start);visited[start] = true;// 开始 BFSwhile (!q.empty()) {int cur = q.front();q.pop();// 更新当前节点被访问的次数visit_count[cur]++;// 遍历反向图中从当前节点可以到达的所有邻居节点for (int next : reverse_graph[cur]) {if (!visited[next]) { // 如果邻居节点未被访问visited[next] = true;q.push(next);}}}
}int main() {int K, N, M; // K:奶牛数, N:牧场数, M:路径数cin >> K >> N >> M;vector<int> cow_start(K); // 每头奶牛所在的初始牧场// 输入奶牛的初始位置for (int i = 0; i < K; ++i) {cin >> cow_start[i];}// 输入路径,并反向建图for (int i = 0; i < M; ++i) {int A, B;cin >> A >> B;reverse_graph[B].push_back(A); // 反向建图:从 B 指向 A}// 初始化访问计数memset(visit_count, 0, sizeof(visit_count));// 对每头奶牛的初始牧场执行 BFSfor (int cow : cow_start) {bfs(cow);}// 统计被所有奶牛访问的牧场数int result = 0;for (int i = 1; i <= N; ++i) { // 遍历所有牧场if (visit_count[i] == K) { // 如果某牧场被 K 头奶牛访问result++;}}// 输出结果cout << result << endl;return 0;
}

输入

2 4 4
2
3
1 2
1 4
2 3
3 4

 

数据解读
  • 奶牛初始位置:

    • 奶牛 1 在牧场 2
    • 奶牛 2 在牧场 3
  • 路径(反向建图):

    • 原始路径 1→2,1→4,2→3,3→4
    • 反向图:
      • 2→1
      • 4→1
      • 3→2
      • 4→3

运行过程
  1. 奶牛 1 的 BFS:

    • 从节点 2 出发,访问节点:2 → 3 → 4。
  2. 奶牛 2 的 BFS:

    • 从节点 3 出发,访问节点:3 → 4。
  3. 统计结果:从每头牛开始遍历,把他经过的牧场访问+1

    • 节点 3 和节点 4 被两头奶牛访问,因此是可行的聚集地点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/60832.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

替代Postman ,17.3K star!

现在&#xff0c;许多人都朝着全栈工程师的方向发展&#xff0c;API 接口的编写和调试已成为许多开发人员必备的技能之一。 工欲善其事&#xff0c;必先利其器。拥有一款优秀的 API 工具对于任何工程师来说都是极为重要的&#xff0c;它能够帮助我们高效地完成各种开发任务。 …

java:拆箱和装箱,缓存池概念简单介绍

1.基本数据类型及其包装类&#xff1a; 举例子&#xff1a; Integer i 10; //装箱int n i; //拆箱 概念&#xff1a; 装箱就是自动将基本数据类型转换为包装器类型&#xff1b; 拆箱就是自动将包装器类型转换为基本数据类型&#xff1b; public class Main {public s…

Node.js的url模块与querystring模块

新书速览|Vue.jsNode.js全栈开发实战-CSDN博客 《Vue.jsNode.js全栈开发实战&#xff08;第2版&#xff09;&#xff08;Web前端技术丛书&#xff09;》(王金柱)【摘要 书评 试读】- 京东图书 (jd.com) 4.3.1 http模块——创建HTTP服务器、客户端 要使用http模块&#xff0…

【Reinforcement Learning】强化学习下的多级反馈队列(MFQ)算法

&#x1f4e2;本篇文章是博主强化学习&#xff08;RL&#xff09;领域学习时&#xff0c;用于个人学习、研究或者欣赏使用&#xff0c;并基于博主对相关等领域的一些理解而记录的学习摘录和笔记&#xff0c;若有不当和侵权之处&#xff0c;指出后将会立即改正&#xff0c;还望谅…

【linux】服务器加装硬盘后如何将其设置为独立硬盘使用

【linux】服务器加装硬盘后如何将其设置为独立硬盘使用 问题描述&#xff1a;本服务器原本使用了两个硬盘作为存储硬盘&#xff0c;同时对这两个硬盘设置了raid1阵列。现在内存不足要进行加载硬盘&#xff0c;新加载的硬盘不设置为raid1&#xff0c;而是将新加装的两个硬盘作为…

亚信安全与飞书达成深度合作

近日&#xff0c;亚信安全联合飞书举办的“走近先进”系列活动正式走进亚信。活动以“安全护航信息化 共筑数字未来路”为主题&#xff0c;吸引了众多数字化转型前沿企业的近百位领导参会。作为“走近先进”系列的第二场活动&#xff0c;本场活动更加深入挖掘了数字化转型的基础…

TMS FNC UI Pack 5.4.0 for Delphi 12

TMS FNC UI Pack是适用于 Delphi 和 C Builder 的多功能 UI 控件的综合集合&#xff0c;提供跨 VCL、FMX、LCL 和 TMS WEB Core 等平台的强大功能。这个统一的组件集包括基本工具&#xff0c;如网格、规划器、树视图、功能区和丰富的编辑器&#xff0c;确保兼容性和简化的开发。…

Transformer详解及衍生模型GPT|T5|LLaMa

简介 Transformer 是一种革命性的神经网络架构&#xff0c;首次出现在2017年的论文《Attention Is All You Need》中&#xff0c;由Google的研究团队提出。与传统的RNN和LSTM模型不同&#xff0c;Transformer完全依赖于自注意力&#xff08;Self-Attention&#xff09;机制来捕…

Git(一)基本使用

目录 一、使用git -v 查看安装git版本 二、使用mkdir 创建一个文件&#xff0c;并使用 git init 在该目录下创建一个本地仓库&#xff0c; 三、通过git clone命令接入线上仓库 四、使用git status查看仓库状态信息 五、利用echo写入一个文件 并使用cat进行查看 【Linux】e…

vue3 uniapp 扫普通链接或二维码打开小程序并获取携带参数

vue3 uniapp 扫普通链接或二维码打开小程序并获取携带参数 微信公众平台添加配置 微信公众平台 > 开发管理 > 开发设置 > 扫普通链接二维码打开小程序 配置链接规则需要下载校验文档给后端存入服务器中&#xff0c;保存配置的时候会校验一次&#xff0c;确定当前的配…

Vercel 设置自动部署 GitHub 项目

Vercel 设置自动部署 GitHub 项目 问题背景 最近 Vercel 调整了其部署政策&#xff0c;免费版用户无法继续使用自动部署功能&#xff0c;除非升级到 Pro 计划。但是&#xff0c;我们可以通过配置 Deploy Hooks 来实现同样的自动部署效果。 解决方案 通过设置 Vercel 的 Dep…

商业物联网:拥抱生产力的未来

在现代商业格局中&#xff0c;数据占据至高无上的地位。物联网&#xff08;IoT&#xff09;站在这场数字革命的前沿&#xff0c;将以往模糊不清的不确定因素转变为可衡量、可付诸行动的深刻见解。物联网技术为日常物品配备传感器与连接功能&#xff0c;使其能够实时收集并传输数…

金融租赁系统助力企业升级与风险管理的新篇章

内容概要 在当今的商业环境中&#xff0c;“金融租赁系统”可谓是企业成功的秘密武器。简单来说&#xff0c;这个系统就像一位聪明的财务顾问&#xff0c;帮助企业在资金和资源的运用上达到最优化。从设备采购到项目融资&#xff0c;它提供了一种灵活的方式&#xff0c;让企业…

java版CRM客户关系管理系统crm管理系统+客户+营销管理CRM平台

项目名称&#xff1a;CRM客户关系管理系统 功能模块及描述&#xff1a; 一、待办事项 今日需联系客户&#xff1a;显示当日需跟进的客户列表&#xff0c;支持查询和筛选。 分配给我的线索&#xff1a;管理分配给用户的线索&#xff0c;包括线索列表和查询功能。 分配给我的客…

【K8S问题系列 |18 】如何解决 imagePullSecrets配置正确,但docker pull仍然失败问题

如果 imagePullSecrets 配置正确&#xff0c;但在执行 docker pull 命令时仍然失败&#xff0c;可能存在以下几种原因。以下是详细的排查步骤和解决方案。 1. 检查 Docker 登录凭证 确保你使用的是与 imagePullSecrets 中相同的凭证进行 Docker 登录&#xff1a; 1.1 直接登录…

基于FPGA的2FSK调制-串口收发-带tb仿真文件-实际上板验证成功

基于FPGA的2FSK调制 前言一、2FSK储备知识二、代码分析1.模块分析2.波形分析 总结 前言 设计实现连续相位 2FSK 调制器&#xff0c;2FSK 的两个频率为:fI15KHz&#xff0c;f23KHz&#xff0c;波特率为 1500 bps,比特0映射为f 载波&#xff0c;比特1映射为 载波。 1&#xff09…

Android 应用测试的各种环境问题记录(Instrumentation测试)

报错记录 failed to configure packages targetSdkVersion&#xff08;未解决&#xff09; failed to configure com.demo.test.SettingsActivityTest.testOnCreate_withNullSavedInstanceState: Package targetSdkVersion34 > maxSdkVersion32 java.lang.IllegalArgumentE…

深度解析:Nginx模块架构与工作机制的奥秘

文章目录 前言Nginx是什么?Ngnix特点&#xff1a; 一、Nginx模块与工作原理1.Nginx的模块1.1 Nginx模块常规的HTTP请求和响应的流程图:1.2 Nginx的模块从结构上分为如下三类&#xff1a;1.3 Nginx的模块从功能上分为如下三类: 2.Nginx的进程模型2.1 Nginx进程结构2.2 nginx进程…

【R语言管理】Pycharm配置R语言及使用Anaconda管理R语言虚拟环境

目录 使用Anaconda创建R语言虚拟环境1. 安装Anaconda2. 创建R语言虚拟环境 Pycharm配置R语言1. 安装Pycharm2. R Language for IntelliJ插件 参考 使用Anaconda创建R语言虚拟环境 1. 安装Anaconda Anaconda的安装可参见另一博客-【Python环境管理工具】Anaconda安装及使用教程…

分布式kettle调度平台v6.4.0新功能介绍

介绍 Kettle&#xff08;也称为Pentaho Data Integration&#xff09;是一款开源的ETL&#xff08;Extract, Transform, Load&#xff09;工具&#xff0c;由Pentaho&#xff08;现为Hitachi Vantara&#xff09;开发和维护。它提供了一套强大的数据集成和转换功能&#xff0c…