P1700 [USACO19OPEN] Milk Factory B

题解:洛谷 P1700 [USACO19OPEN] Milk Factory B 不幸的是,当他意识到传送带是单向的已经太晚了,现在每条通道只能沿着一个方向通行了!所以现在的情况不再是从每个加工站出发都能够到达其他加工站了。题目涵盖了从基础到进阶的多种算法和数据结构,旨在为不同阶段的编程学习者提供一条清晰、平稳的学习提升路径。条通道,每条连接某两个加工站。(通道建设很昂贵,所以 Farmer John 选择使用了最小数量的通道,使得从每个加工站出发都可以到达所有其他加工站)。满足可以从任意其他加工站出发都可以到达加工站。满足从其他每个加工站出发都可以到达加工站。,输出最小的满足条件的。 阅读详情

记录137

#include<bits/stdc++.h>
using namespace std;
const int N=105;// 定义常量N,表示加工站数量的最大范围(题目保证N<=100)
vector<int> g[N];// 定义邻接表g,g[u]存储从结点u出发能直接到达的所有结点
bool vis[N];// 定义访问标记数组,用于DFS时防止重复访问
bool found_target=0; // 定义标志变量,用于在DFS中记录是否成功找到了目标点target
// 深度优先搜索(DFS)函数,从当前结点u出发,寻找目标点target
void dfs(int u,int target){
	if(found_target) return; // 如果之前已经找到了目标点,直接剪枝返回
	if(u==target){ // 如果当前结点u就是目标点target
		found_target=1; // 标记已找到目标点
		return; // 直接返回
	}
	vis[u]=1; // 标记当前结点u已被访问过
	for(int v:g[u]){ // 遍历当前结点u能到达的所有相邻结点v
		if(!vis[v]) dfs(v,target); 
	}// 如果结点v还没有被访问过,继续从v出发进行深搜 
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n;// 定义变量n,表示加工站的数量
	cin>>n; // 读入加工站数量n
	int a,b; // 定义变量a和b,用来临时存储每条传送带的起点和终点
	for(int i=1;i<n;i++){ //n-1条边 
		cin>>a>>b; // 读入一条从a指向b的传送带
		g[a].push_back(b);  // 将b加入a的邻接表(表示a能走到b) 
	}
	// 从小到大枚举每一个结点i作为终点
	for(int i=1;i<=n;i++){ 
		bool is_ok=1; // 假设当前目标是合法的
		// 检查所有其他结点j,看是否都能通过DFS走到目标i 
		for(int j=1;j<=n;j++){
			if(j==i) continue;  // 如果j就是目标本身,不需要检查
			memset(vis,0,sizeof(vis)); //走之前重置访问数组 
			found_target=0; // 一开始没找到目标 
			dfs(j,i); // 从结点j出发,尝试寻找目标i 
			if(!found_target){ // 如果从j出发无法走到目标i 
				is_ok=0; // 当前目标不合法
				break; //提前跳出内层循环,检查下一个target 
			}
		}
		if(is_ok){ // 如果当前i满足所有结点都能到达它
			cout<<i<<"\n"; // 输出最小的满足条件的i
			return 0; // 程序直接结束
		}
	}
	cout<<-1; // 如果遍历完所有target都不合法,输出-1
	return 0;//程序正常结束
}

题目传送门https://www.luogu.com.cn/problem/P1700


前言

我是一名专注信奥赛(CSP-J/S、NOIP)的教练。

  • 如果你觉得这篇题解对你有帮助,欢迎点击关注我的优快云账号,我会持续更新高质量算法解析。
  • 我深知算法思维的构建远比单纯通过题目更重要,本系列题解不局限于AC代码的堆砌,而是致力于拆解题目背后的逻辑链条与核心知识点
  • 备赛路上若遇瓶颈,欢迎随时评论或私信,我将甄选典型疑难问题,通过视频讲解或撰写专项文章的形式,为你提供深度答疑。

核心解题思路

这道题是一道典型的图论与暴力枚举结合的问题。

  1. 问题转化:
    题目给出了一个包含 NN 个结点和 N−1N−1 条有向边的图(本质是一棵有向树)。我们需要找到一个结点 ii ,使得图中所有其他结点都能通过有向边到达 ii 。如果存在多个这样的结点,输出编号最小的那个;如果不存在,输出 -1。

  2. 算法设计(暴力枚举 + DFS):
    由于题目中 NN 的最大值仅为 100,数据规模非常小。我们可以采用最直观的暴力枚举法:

    • 依次假设每一个结点 ii (从 1 到 NN )是我们要找的“终点”。
    • 对于每一个假设的终点 ii ,我们从图中的每一个其他结点 jj 出发,使用深度优先搜索(DFS)或广度优先搜索(BFS),判断是否能沿着有向边到达 ii 。
    • 如果所有结点 jj 都能到达 ii ,那么 ii 就是合法的答案。因为我们是从 1 开始从小到大枚举的,所以找到的第一个合法 ii 必然是最小的。

 代码分块详细解释

1. 头文件、常量与全局变量定义

#include<bits/stdc++.h>
using namespace std;
const int N=105; // 定义常量 N,表示加工站数量的最大范围(题目保证 N<=100)
vector<int> g[N]; // 定义邻接表 g,g[u] 存储从结点 u 出发能直接到达的所有结点
bool vis[N]; // 定义访问标记数组,用于 DFS 时防止重复访问
bool found_target=0; // 定义标志变量,用于在 DFS 中记录是否成功找到了目标点 target
  • 详细分析:这部分搭建了图论算法的基础。由于是有向图,我们使用 vector<int> g[N] 来构建邻接表,g[a].push_back(b) 表示存在一条从 aa 指向 bb 的单向传送带。vis 数组是 DFS 的标配,防止在图中走环路导致死循环。found_target 是一个全局剪枝变量,一旦在某次 DFS 中找到了目标,就立刻停止后续的搜索,提高效率。

2. 深度优先搜索(DFS)函数

// 深度优先搜索(DFS)函数,从当前结点 u 出发,寻找目标点 target
void dfs(int u, int target){
    if(found_target) return; // 如果之前已经找到了目标点,直接剪枝返回
    if(u == target){ // 如果当前结点 u 就是目标点 target
        found_target = 1; // 标记已找到目标点
        return; // 直接返回
    }
    vis[u] = 1; // 标记当前结点 u 已被访问过
    for(int v : g[u]){ // 遍历当前结点 u 能到达的所有相邻结点 v
        if(!vis[v]) dfs(v, target); 
    } // 如果结点 v 还没有被访问过,继续从 v 出发进行深搜 
}
  • 详细分析:这是判断“点 jj 能否到达点 ii ”的核心工具。
    • 剪枝优化:函数开头首先检查 found_target,如果之前的搜索路径已经找到了目标,当前递归分支就没有继续的必要了,直接返回。
    • 命中目标:如果当前遍历到的结点 u 等于目标 target,说明路径打通,将全局标志置为 1 并返回。
    • 递归扩展:如果没有找到目标,就标记当前点已访问,然后遍历它的所有出边。只有当相邻结点 v 未被访问时,才递归进入,这保证了搜索的有限性。

3. 主函数:建图与输入处理

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n; // 定义变量 n,表示加工站的数量
    cin >> n; // 读入加工站数量 n
    int a, b; // 定义变量 a 和 b,用来临时存储每条传送带的起点和终点
    for(int i = 1; i < n; i++){ // n-1 条边 
        cin >> a >> b; // 读入一条从 a 指向 b 的传送带
        g[a].push_back(b);  // 将 b 加入 a 的邻接表(表示 a 能走到 b) 
    }
  • 详细分析:标准的 IO 加速和建图过程。题目给出了 N−1N−1 条有向边,我们按照输入顺序,将每条边的终点加入起点的邻接表中,从而构建出完整的有向图。

4. 核心逻辑:枚举终点与合法性检查

    // 从小到大枚举每一个结点 i 作为终点
    for(int i = 1; i <= n; i++){ 
        bool is_ok = 1; // 假设当前目标是合法的
        // 检查所有其他结点 j,看是否都能通过 DFS 走到目标 i 
        for(int j = 1; j <= n; j++){
            if(j == i) continue;  // 如果 j 就是目标本身,不需要检查
            memset(vis, 0, sizeof(vis)); // 走之前重置访问数组 
            found_target = 0; // 一开始没找到目标 
            dfs(j, i); // 从结点 j 出发,尝试寻找目标 i 
            if(!found_target){ // 如果从 j 出发无法走到目标 i 
                is_ok = 0; // 当前目标不合法
                break; // 提前跳出内层循环,检查下一个 target 
            }
        }
        if(is_ok){ // 如果当前 i 满足所有结点都能到达它
            cout << i << "\n"; // 输出最小的满足条件的 i
            return 0; // 程序直接结束
        }
    }
    cout << -1; // 如果遍历完所有 target 都不合法,输出 -1
    return 0; // 程序正常结束
}
  • 详细分析:这是算法的主体部分,采用了双重循环。
    • 外层循环(枚举假设):我们依次假设结点 ii 是那个“所有点都能到达的终点”。因为题目要求输出最小的 ii ,所以我们从 1 开始从小到大枚举,一旦找到合法的就可以直接输出并结束程序。
    • 内层循环(验证假设):对于当前的假设终点 ii ,我们需要验证图中的每一个其他结点 jj 是否都能到达它。
    • 状态重置:每次从一个新的起点 jj 开始 DFS 之前,必须将访问数组 vis 清零,并将 found_target 重置为 0。这是因为每次 DFS 都是一次全新的探索。
    • 提前终止:如果在验证过程中,发现有任何一个结点 jj 无法到达 ii (即 !found_target),那么当前的 ii 肯定不是答案,直接 break 跳出内层循环,去测试下一个 ii 。这极大地减少了不必要的计算。

核心逻辑总结表

代码模块核心变量/操作精炼作用解决的痛点
数据结构vector<int> g[N]使用邻接表存储有向图高效存储单向传送带,方便通过起点快速找到所有能直接到达的终点
路径搜索dfs(u, target)判断从 u 到 target 是否有通路解决有向图中两点连通性的判断问题
防死循环vis[u]=1 与 if(!vis[v])记录已访问的结点防止在 DFS 过程中因为图中存在环路或重复路径而导致无限递归
全局剪枝found_target记录目标是否已被找到一旦在 DFS 的某条分支中找到了目标,立即停止所有后续搜索,提升效率
暴力枚举双重 for 循环依次假设每个点为终点并验证利用 N≤100N≤100 的小数据范围,用简单直观的暴力法替代复杂的图论算法
Flutter加载本地HTML的优雅解决方案:轻松实现富文本展示 通过以上步骤,我们实现了Flutter加载本地HTML的完整流程,并简单介绍了如何通过WebView与HTML页面进行交互。HTML文件作为一种灵活、易维护的富文本展示方式,能有效提升Flutter应用的内容呈现能力。这种方法在展示新闻、资讯或帮助文档等内容时非常有用,能够让开发者灵活调整内容的样式和排版。希望这篇文章能对你在Flutter开发中的HTML加载有所帮助! 阅读详情

相关推荐

避坑指南:ROS2 Humble摄像头标定常见错误排查(从‘CALIBRATE’按钮不变绿到保存文件找不到)

本文详细解析了ROS2 Humble环境下摄像头标定的常见问题及解决方案,从CALIBRATE按钮不变绿到标定文件保存失败等疑难杂症。提供硬件准备、参数设置、实时诊断到结果验证的全流程指导,特别针对Ubuntu2204系统和usb_cam驱动的兼容性问题给出实用建议,帮助开发者高效完成内参标定。

weixin_29193359的博客 398

P1700 [USACO19OPEN] Milk Factory B 题解(小白友好版)

牛奶工厂中央站问题解析 核心思路:通过构建反向传送带图,将原问题转化为从中央站出发能否到达所有站点的问题,利用BFS算法高效求解。 关键步骤: 输入N个站点及其传送带信息 构建反向图(将原传送带方向反转) 对每个候选站点执行BFS: 检查从该站出发能否访问所有站点 使用队列实现广度优先搜索 统计已访问站点数 输出第一个满足条件的站点编号,否则输出-1 算法优势: 时间复杂度O(N²)高效处理小规模数据(N≤100) 反向图转换巧妙简化问题 BFS确保可达性检查的完整性 学习价值:掌握图论中的反向思维和基本遍

Sanhai的博客 984

STM32与小米CyberGear微电机的CAN通信协议深度解析

本文深度解析STM32与小米CyberGear微电机的CAN通信协议,涵盖硬件连接、CAN总线配置、通信协议解析及多电机协同控制。重点介绍了基于STM32的电机控制实践,包括运动模式、速度与位置模式设置,以及数据反馈与故障诊断,为机器人及自动化设备开发提供实用指南。

www00的博客 362

洛谷.P1700 [USACO19OPEN] Milk Factory B

洛谷,C++,菜菜奋斗日记

2402_88149600的博客 343

手把手教你用Anaconda安装李沐d2l-zh包(附常见报错解决方案)

本文提供了一份详尽的Anaconda环境下安装李沐d2l-zh包的实战指南。文章从创建虚拟环境、配置国内镜像源加速下载入手,分步讲解核心依赖的预安装策略,并重点剖析了安装过程中常见的报错及其解决方法,旨在帮助初学者和开发者高效、稳定地搭建深度学习实验环境。

efc1234567的博客 1011

GraphRAG 与 HippoRAG 深度对比:在 RAGFlow 中如何选择知识图谱方案?

本文深入对比了GraphRAG与HippoRAG在RAGFlow中的知识图谱构建方案,分析了两者在技术架构、资源消耗和场景适配性上的核心差异。GraphRAG适合需要快速响应和资源有限的场景,而HippoRAG则更适用于精确关系推理的专业领域。文章还提供了RAGFlow的演进路线和选型决策框架,帮助架构师根据实际需求做出合理选择。

weixin_27889245的博客 247

洛谷 P1700 [USACO19OPEN] Milk Factory B C语言

然而,Farmer John 认为事情可能还不算完全失败,只要至少还存在一个加工站 ii 满足从其他每个加工站出发都可以到达加工站 i。这表示有一条从加工站 ai​ 向加工站 bi​ 移动的传送带,仅允许沿从 ai到 bi​ 的方向移动。我们可以使用反向建立边,也就是说,存在一个点可以到达任何点,所以我们需要一个计数器cnt,如果cnt等于n那么就找到了,输出下标,如果没有那就是找不到了输出-1。如果存在加工站 ii 满足可以从任意其他加工站出发都可以到达加工站 i,输出最小的满足条件的 i。

zqystca的博客 742

SAP S/4HANA 数据归档的实施方法

实施 SAP S/4HANA 数据归档是一个系统的过程,涉及到策略的定义、技术的执行以及后续的维护和验证。正确的归档策略不仅能优化系统性能,还能帮助企业降低运营成本,确保数据安全,并符合相关法律法规的要求。通过以上案例,我们可以看到不同行业如何依据自己的业务需求和法规要求,利用 SAP S/4HANA 的强大功能来实现数据归档的目标。这些实践证明了数据归档在现代企业信息管理中的重要地位和作用。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 890

打卡信奥刷题(210)用C++信奥P1700[普及组/提高] [USACO19OPEN] Milk Factory B

牛奶生意正红红火火!Farmer John 的牛奶加工厂内有N个加工站,编号为1N1≤N≤100),以及N−1条通道,每条连接某两个加工站。(通道建设很昂贵,所以 Farmer John 选择使用了最小数量的通道,使得从每个加工站出发都可以到达所有其他加工站)。为了创新和提升效率,Farmer John 在每条通道上安装了传送带。不幸的是,当他意识到传送带是单向的已经太晚了,现在每条通道只能沿着一个方向通行了!所以现在的情况不再是从每个加工站出发都能够到达其他加工站了。

Loge谈信奥--一个专注于信奥人的博客 2769

计算机组成原理(第三版)唐朔飞-第六章计算机的运算方法-课后习题(1-16)

计算机组成原理(第三版)唐朔飞-第六章计算机的运算方法-课后习题(1-16)

weixin_45735391的博客 8万+

学Simulink--基础微电网场景实例:基于Simulink的微电网并网/孤岛无缝切换控制仿真

本文完成了基于 Simulink 的微电网并网/孤岛无缝切换控制仿真,实现了:✅ 构建含双模式逆变器的微电网模型✅ 实现预同步 + Stateflow 逻辑的智能切换✅ 验证计划与非计划切换的性能边界✅ 证明“无缝”在工程上是可实现的。

amy_mhd的博客 103

洛谷 P1700 [USACO19OPEN] Milk Factory B

我们利用vector容器记录一个点可以作为哪些点的“头”,然后就从最小的点开始暴力bfs,在bfs之前,初始化一下vis数组用以记录每个点有没有被放入过。在bfs过程中,我们每次取队列的第一个元素(队列不为空),然后将以第一个元素为“头”的且没有放入过队列的元素入队,记录最后入队次数是否等于n,如果等于,直接输出即可。

2302_79954861的博客 267

GibbsCAM软件二次开发:GibbsCAM软件API接口详解

API(Application Programming Interface,应用程序编程接口)是一种允许不同软件之间进行通信的接口。在GibbsCAM软件中,API提供了与外部程序交互的能力,使得开发者可以利用GibbsCAM的强大功能进行二次开发,定制化满足特定的制造需求。GibbsCAM的API主要基于.NET框架,使用C#或VB.NET等语言进行编程。在GibbsCAM软件中,通过API接口创建自定义几何形状是实现复杂零件设计和加工策略定制的关键步骤。

kkchenjj的博客 1497

洛谷 - P5836 [USACO19DEC]Milk Visits S (并查集+连通块或者LCA)

题目传送 题意: 思路: 1.那么他给定了n个点,n-1条边的无向图,又说了这个图是相互连通的,那么一个点到另外一个点的路径是唯一的。 2.既然路径是唯一的,那么我们就看路径的性质,如果这条路径上面又有G又有H,那么无论谁走这条路都会高兴的。而如果这条路上只有H或者G,那么当喜欢另一种口味的人,走这条路就会不高兴 3.所以找出其特性:给定俩个点,路径唯一,只有当这条路的字符一样的时候,才有可能使客人不高兴,而字符一样,那不就是具有相同的性质吗?用并查集将字符一样的边连通,后面再判断就是。 LCA我还不会

give it a try 480

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Milk Factory//排位2

Milk Factory//暴力? 题目 The milk business is booming! Farmer John’s milk processing factory consists of N processing stations, conveniently numbered 1…N (1≤N≤100), and N−1 walkways, each connecting some...

salty_fishman的博客 706

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

【题解】LuoGu5423:[USACO19OPEN]Valleys P

原题传送门 根据两个式子展开的题目 首先按照高度从小到大排序好之后按顺序加点 对于新加的这个点,在四周四个点,如果已经加入了,就合并,用并查集维护 然后判断新加的点所属的连通块知否合法 F=E+2−V,即块数=边数+2−点数F=E+2-V,即块数=边数+2-点数F=E+2−V,即块数=边数+2−点数 F=1(边界框起来的一个大块)+元环个数+洞个数F=1(边界框起来的一个大块)+元环个数+洞个数F=1(边界框起来的一个大块)+元环个数+洞个数 定义元环为一个单位小正方形,就是四个点都已经加入的 然后合法就意

ModestCoder_的博客 708

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

USACO P1700 Milk Factory B题解:从有向图可达性到反向建图与拓扑排除法

有向图是图论中最基础也最核心的模型之一,描述的是节点之间单向的依赖或传递关系。在算法竞赛与工程实践中,判断“从某个点能否到达另一个点”是常见问题,通常借助深度优先搜索(DFS)或广度优先搜索解决。当问题需要寻找一个被所有节点共同到达的“汇聚点”时,直接枚举每个起点会稍显繁琐,而反向建图的思想能巧妙地将“所有点可达某点”转化为“某点可达所有点”,大幅简化判断逻辑。此外,拓扑排序中的入度删除策略也提供了一种线性复杂度的排除法视角,适合处理更大规模的数据。这类模型广泛应用于社交网络影响力分析、任务调度、依赖解析等

weixin_42520374的博客 153

USACO历年青铜组真题解析 | 汇总

我把自己练习过的USACO的题目都整理了一下。虽然网站上有许多高手的解法,但因为我自己也是初学者,所以只用了比较容易理解的方法来分析和解答。如果你也在学习的话,希望这些内容能对你有一点帮助。

团爸讲算法 5671

视频隐私脱敏工程化:CSRT/KCF追踪算法在本地推理中的实现与边界

在短视频内容合规审查中,动态遮挡(Dynamic Masking)是高频且高耗时的环节。传统手动关键帧打码不仅效率低下,且在目标快速移动或遮挡时极易出现遮罩漂移。本文从计算机视觉工程角度,解析基于CSRT与KCF算法的目标追踪方案在视频隐私处理中的技术路径、性能权衡及落地实践。

Mysssone的博客 296

把 KV Cache 压到 FP4:BitDecoding-FP4 的算法-系统协同设计复盘

长上下文推理卡在KV Cache的显存与带宽上,而现有FP4方案要么精度崩、要么速度废。这篇文章复盘BitDecoding-FP4如何用三个算法补丁加一个系统重构,在B300上把服务吞吐提升2.4–3.0倍,精度几乎不掉。

helloagent的博客 308

【算法拾光】链表 哈希表|K个一组翻转链表 + 两数之和

K个一组翻转链表需分段反转,借助哑节点与前驱指针维护连接,避免断链;两数之和利用哈希表实现O(1)查找,空间换时间,高效定位目标组合。前者考察链表指针操作,后者聚焦映射关系构建,均为面试高频题。

wuqingyigexiaoba的博客 328

排序算法深度笔记(下):非比较类排序的线性突破与工程边界

排序算法时间复杂度额外空间复杂度稳定性是否基于比较选择排序O(N^2)(O(1))不稳定是冒泡排序O(N^2)(O(1))稳定是插入排序O(N^2)(O(1))稳定是归并排序O(N\log N)(O(N))稳定是快速排序O(N\log N)O(log N)不稳定是堆排序O(N\log N)O(1)不稳定是计数排序(O(N + M))O(M))稳定否基数排序O(N)稳定否桶排序平均O(N) / 最坏O(N^2)

2401_87069538的博客 601

优选算法:分治-归并排序

交易逆序对的总数

Wangshijie1015的博客 144

算法日常・每日刷题--<动态规划>42

本题为“不相交的线”,与最长公共子序列问题相似。使用动态规划求解:定义 dp[i][j] 表示 nums1[0:i] 与 nums2[0:j] 的最大不相交连线数。若元素相等,则继承左上值加1;否则取上方或左方最大值。最终返回 dp[m][n],即两数组的最大不相交连线数。时间复杂度 O(mn),空间复杂度 O(mn)。

2503_92261635的博客 23
上一篇: P1014 [NOIP 1999 普及组] Cantor 表
下一篇: P9011 [USACO23JAN] Air Cownditioning II B
谢天谢地AC了 | 信奥教练
博客等级 码龄1年 53粉丝 177原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值