從 “模板” 到 “場景”,用 C++ 磨透拓撲排序的實戰邏輯

在這里插入圖片描述
在這里插入圖片描述

文章目錄

  • 前言:
    • 《算法磨劍: 用C++思考的藝術》 專欄
    • 《C++:從代碼到機器》 專欄
    • 《Linux系統探幽:從入門到內核》 專欄
  • 正文:
    • [B3644 【模板】拓撲排序 / 家譜樹](https://www.luogu.com.cn/problem/B3644)
      • 【解法】
        • 【參考代碼】
    • [P2712 攝像頭](https://www.luogu.com.cn/problem/P2712)
      • 【解法】:
      • 【參考代碼】
    • [P4017 最大食物鏈計數](https://www.luogu.com.cn/problem/P4017)
      • 【解法】
      • 【參考代碼】
    • 3 :[P1113 雜務](https://www.luogu.com.cn/problem/P1113)
      • 【解法】
  • 結語:

前言:

《算法磨劍: 用C++思考的藝術》 專欄

專注用C++破解算法面試真題,詳解LeetCode熱題,構建算法思維,從容應對技術挑戰。

👉 點擊關注專欄


《C++:從代碼到機器》 專欄

深入探索C++從語法特性至底層原理的奧秘,構建堅實而深入的系統編程知識體系。

👉 點擊關注專欄


《Linux系統探幽:從入門到內核》 專欄

深入Linux操作系統腹地,從命令、腳本到系統編程,探索Linux的運作奧秘。

👉 點擊關注專欄


作者:孤廖
學習方向:C++/Linux/算法
人生格言:折而不撓,中不為下

正文:

B3644 【模板】拓撲排序 / 家譜樹

在這里插入圖片描述

【解法】

【參考代碼】
#define _CRT_SECURE_NO_WARNINGS
//B3644 【模板】拓撲排序 / 家譜樹
#include <iostream>
#include <vector>
#include <queue>
using namespace std;const int N = 110;
vector<int> edges[N];//edges[i]:表示i節點的孩子 鄰接表(孩子表示法)
int d[N];//d[i]:i節點的入度數
int n;
int main()
{cin >> n;//處理圖的信息for (int i = 1; i <= n; i++){int j;while (cin >> j, j){edges[i].push_back(j);d[j]++;//更新每個節點的入度數}}//拓撲排序queue<int> q;//先把入度數為0 的點 加入隊列for (int i = 1; i <= n; i++) if (d[i] == 0) q.push(i);while (q.size()){int a = q.front(); q.pop();///出隊cout << a << " ";//更新入度數for (auto& e : edges[a]){d[e]--;if (d[e] == 0) q.push(e);}}return 0;
}

P2712 攝像頭

在這里插入圖片描述

【解法】:

拓撲排序判斷是否有環。
直接跑?遍拓撲排序,然后統計?下有多少攝像頭沒有出隊。那么這些沒有出隊的攝像頭就是環??的元素。
注意:
? 有些位置可能沒有攝像頭,需要判斷?下。

【參考代碼】

#define _CRT_SECURE_NO_WARNINGS
//P2712 攝像頭#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int N = 510;
vector<int> edges[N];//edges[i]:表示i 的邊的信息即i指向的孩子
int n;//攝像頭的個數
int d[N];//d[i]:表示節點i的入度數
bool st[N];//st[i]:表示i位置是否有攝像頭
int main()
{cin >> n;//輸入攝像頭的信息 即圖的信息for (int i = 1; i <= n; i++){int x, m, y;cin >> x >> m;st[x] = true;while (m--){cin >> y;edges[x].push_back(y);//統計節點入度數d[y]++;}}//拓撲排序queue<int> q;//將入度數 為0的攝像頭入隊for (int i = 0; i <= 500; i++){if (d[i] == 0 && st[i] ) q.push(i);}while (q.size()){//將入度數為0的攝像頭 出隊int a = q.front(); q.pop();//更新與a攝像頭相關的攝像頭的入度數for (auto& e : edges[a]){d[e]--;if (st[e] && d[e] == 0) q.push(e);}}//遍歷所有位置找到是否還有沒有砸壞的攝像頭int ret = 0;//還沒砸掉的攝像頭數量for (int i = 0; i <= 500; i++){if (st[i] && d[i]) ret++;}if (ret == 0) cout << "YES " << endl;else cout << ret << endl;return 0;
}

P4017 最大食物鏈計數

在這里插入圖片描述
在這里插入圖片描述

【解法】

注意審題!題?問的是?共有多少條路徑!
拓撲排序的過程中,進?動態規劃。
對于每?個節點 ,通過它的路徑為:前驅所有結點的路徑總數之和。因此,可以在拓撲排序的過程中,維護從起點開始到達每?個節點的路徑總數。

【參考代碼】

#define _CRT_SECURE_NO_WARNINGS//P4017 最大食物鏈計數#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int N = 5010,M=5e5+10,MOD= 80112002;int f[N];//f[i]:表示從生產者到i種生物的最大食物鏈條數
vector<int> edges[M];//邊數
int in[N];//in[i]:表示:i種能被多少種生物吃掉即入度數
int out[N];//out[i]:表示:i種生物能吃多少種生物即出度數
int n, m;//物種的個數 和食物鏈的條數
int main()
{cin >> n >> m;for (int i = 1; i <= m; i++){int x, y;//x->ycin >> x >> y;//統計邊的信息,和每個節點 的出入度情況edges[x]. push_back(y);in[y]++;out[x]++;}//dp+拓撲排序//初始化 初始化生產者的最大食物鏈條數 即為1queue<int> q;for (int i = 1; i <= n; i++){if (in[i] == 0){f[i] = 1;//初始化q.push(i);//生產者入隊}}while (q.size()){int a = q.front(); q.pop();//入度數為0的生物出隊//更新a的捕食者的最大生物鏈條數for (auto& e : edges[a]){//a->ein[e]--;f[e] = (f[e] + f[a]) % MOD;//模加模防止溢出if (in[e] == 0)  q.push(e);}}//統計不同食物網最大的食物鏈條數總和int ret = 0;//結果for (int i = 1; i <= n; i++){if (out[i] == 0) ret = (ret + f[i]) % MOD;//模加模防止溢出}//輸出結果cout << ret << endl;return 0;
}

3 :P1113 雜務

在這里插入圖片描述
在這里插入圖片描述

【解法】

拓撲排序的過程中,進?動態規劃。
對于每?個事件 ,完成它的最?時間為:完成前驅所有事件的最?時間中的最?值 + 當前事件的完
成時間。因此,可以在拓撲排序的過程中,維護每?個事件完成的最?時間,然后更新當前事件的最?時間。

第一種初始化下:


#define _CRT_SECURE_NO_WARNINGS
//P1113 雜務#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int N = 1e4 + 10;
int f[N];//f[i]:i雜物完成所需的最小時間
int n;//n 個雜物
vector<int> edges[N];//edges[i]:雜物i完成后能完成的雜物
int len[N];//len[i]:雜物i完成需要的時間
int in[N];//in[i]:雜物i的入度即做雜物i前 需要完成的其他雜物個數
int main()
{cin >> n;for (int i = 1; i <= n; i++){int b = 0, a = 0;//當前雜物b 作雜務b前需要完成的雜物acin >> b >> len[b];while (cin >> a, a){edges[a].push_back(b);in[b]++;}}//dp +拓撲排序//默認初始化int ret = 0;//結果queue<int> q;for (int i = 1; i <= n; i++){if (in[i] == 0) q.push(i);}while (q.size()){int pre = q.front(); q.pop();//出隊f[pre] += len[pre];ret = max(ret, f[pre]);//更新后續要完成雜物的最小時間for (auto& e : edges[pre]){in[e]--;f[e] = max(f[e], f[pre]);if (in[e] == 0) q.push(e);}}//輸出結果cout << ret << endl;return 0;
}

第二種初始化下

#define _CRT_SECURE_NO_WARNINGS
//P1113 雜務#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int N = 1e4 + 10;
int f[N];//f[i]:i雜物完成所需的最小時間
int n;//n 個雜物
vector<int> edges[N];//edges[i]:雜物i完成后能完成的雜物
int len[N];//len[i]:雜物i完成需要的時間
int in[N];//in[i]:雜物i的入度即做雜物i前 需要完成的其他雜物個數
int main()
{cin >> n;for (int i = 1; i <= n; i++){int b = 0, a = 0;//當前雜物b 作雜務b前需要完成的雜物acin >> b >> len[b];while (cin >> a, a){edges[a].push_back(b);in[b]++;}}//dp +拓撲排序//初始化int ret = 0;//結果queue<int> q;for (int i = 1; i <= n; i++){if (in[i] == 0){q.push(i);f[i] = len[i];}}while (q.size()){int pre = q.front(); q.pop();//出隊//更新后續要完成雜物的最小時間ret = max(ret, f[pre]);for (auto& e : edges[pre]){in[e]--;f[e] = max(f[e], len[e] + f[pre]);if (in[e] == 0) q.push(e);}}//輸出結果cout << ret << endl;return 0;
}



結語:

這篇拓撲排序專題,我們從四道洛谷題里挖出了算法 “不變的核心” 與 “多變的場景”——B3644 作為模板題,用 C++ 的vector鄰接表 +queue搭好了 Kahn 算法的基礎框架,讓 “入度維護 + 節點遍歷” 的邏輯變得直觀P2712 攝像頭則在模板上加了 “環檢測” 的實際需求,靠 “拓撲序列長度與節點數對比” 快速破題,C++ 的st數組又幫我們精準篩選出有攝像頭的位置,避免無效計算;P4017 最大食物鏈計數更巧妙,把拓撲排序和 DP 結合,用f數組同步累加路徑數,模運算的細節處理還兼顧了數據溢出問題;而 P1113 雜務則聚焦 “最長路徑”,兩種初始化方式的對比,讓我們看清f數組維護 “前置任務最大時間” 的本質,也體會到 C++ 代碼實現的靈活性。

其實拓撲排序的魅力,就在于它能把 “依賴關系” 轉化為 “可計算的順序”,而 C++ 則是把這種思路落地的關鍵 —— 選queue還是priority_queue,用數組還是vector存狀態,甚至初始化的時機,都會影響代碼的效率與可讀性。這也是 “算法磨劍” 的意義:不只是會背模板,更是能根據題目場景,用 C++ 把算法 “磨” 成貼合需求的工具。

如果這篇解析幫你理清了拓撲排序的不同應用場景,或是對 C++ 實現細節有了新理解,不妨點個贊 + 收藏,方便后續復盤;也歡迎在評論區分享你的思考:你解 P2712 時有沒有先想到其他判環方法?P1113 的兩種初始化方式,你更偏愛哪種邏輯?后續 “算法磨劍:用 C++ 思考的藝術” 專欄還會繼續深挖圖論、動態規劃等算法的實戰場景,陪你從 “會用算法” 到 “用好算法”,在代碼里一步步精進!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/96357.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/96357.shtml
英文地址,請注明出處:http://en.pswp.cn/web/96357.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

盲盒抽卡機小程序:從0到1的蛻變之路

盲盒抽卡機小程序從概念提出到最終上線&#xff0c;經歷了從0到1的蛻變過程。這個過程充滿了挑戰與機遇&#xff0c;也凝聚了開發團隊的智慧和汗水。本文將分享盲盒抽卡機小程序的開發歷程&#xff0c;探討其背后的技術實現和市場策略。需求分析&#xff1a;明確目標用戶與市場…

分層-三層架構

文章目錄介紹代碼拆分Dao層server層controller層運行結果介紹 在我們進行程序設計以及程序開發時&#xff0c;盡可能讓每一個接口、類、方法的職責更單一些&#xff08;單一職責原則&#xff09;。 單一職責原則&#xff1a;一個類或一個方法&#xff0c;就只做一件事情&#…

Vue2 VS Vue3

vue3 是的&#xff0c;Vue 3 確實取消了基于 JavaScript 原型的 Vue 和 VueComponent 構造函數&#xff08;即你提到的 vm 和 vc&#xff09;&#xff0c;取而代之的是一種完全不同的、基于普通對象和代理&#xff08;Proxy&#xff09;的實例管理方式。 這是一個顛覆性的改變…

Vue3入門到實戰,最新版vue3+TypeScript前端開發教程,Vue3簡介,筆記02

筆記02 一、Vue3簡介 1.1、Vue3發布日期&#xff1a; 2020年9月18日 1.2、Vue3做了哪些升級&#xff1a; 1.2.1、性能的提升 官方發版地址&#xff1a;Release v3.0.0 One Piece vuejs/core 打包大小減少41%初次渲染快55%更新渲染快133%內容減少54% 1.2.2、源碼的優化…

.net core webapi/mvc阿里云服務器部署 - 錯誤解決

錯誤及解決方案缺少web.config配置HTTP 錯誤 500.19 - Internal Server Error檢查 IIS 配置1. 確保 .NET Core Hosting Bundle 已安裝2. 檢查 應用程序池 配置3. 檢查 IIS MIME 類型檢查文件權限1. 確保 IIS 用戶 有權限訪問網站目錄2. 檢查 web.config 文件權限啟用詳細錯誤日…

多輸入(input)多輸出(output)驗證

#作者&#xff1a;程宏斌 文章目錄前言Flb 1.9.4 INCLUDE配置測試測試方案測試配置文件測試命令Flb 3.0.2 INCLUDE配置測試測試方案測試配置文件啟動命令結論結論一&#xff1a;結論二&#xff1a;前言 需要設計并執行一組測試用例&#xff0c;這些測試用例將包括以子文件形式…

行業學習【電商】:垂直電商如何理解?以專業寵物平臺為例

聲明&#xff1a;以下部分內容含AI生成 “寵物等愛好者的專業平臺”指的是垂直電商的一個具體例子。 “垂直電商” 就是指不賣所有東西&#xff0c;只深耕某一個特定領域&#xff08;即“垂直”領域&#xff09;的電商平臺。 “寵物愛好者的專業平臺”就是這樣一個專門為養寵…

GPT(Generative Pre-trained Transformer)模型架構與損失函數介紹

目錄 一、核心架構&#xff1a;Transformer Decoder 1. 核心組件&#xff1a;僅解碼器&#xff08;Decoder-Only&#xff09;的堆疊 2. 輸入表示&#xff1a;Token 位置 3. 輸出 二、訓練過程&#xff1a;兩階段范式 階段一&#xff1a;預訓練&#xff08;Pre-training&…

GitHub 熱榜項目 - 日榜(2025-09-10)

GitHub 熱榜項目 - 日榜(2025-09-10) 生成于&#xff1a;2025-09-10 統計摘要 共發現熱門項目&#xff1a;15 個 榜單類型&#xff1a;日榜 本期熱點趨勢總結 本期GitHub熱榜呈現三大技術熱點&#xff1a;LLM智能體應用爆發&#xff08;如parlant、AutoAgent&#xff09;&a…

論文閱讀:arxiv 2023 Large Language Models are Not Stable Recommender Systems

總目錄 大模型相關研究&#xff1a;https://blog.csdn.net/WhiffeYF/article/details/142132328 https://arxiv.org/pdf/2312.15746 速覽 破解大語言模型在推薦系統中的不穩定性 該論文聚焦于大語言模型&#xff08;LLMs&#xff09;在推薦系統中的應用問題&#xff0c;指出…

Linux的使用——FinalShell下載使用及連接云服務器的教程

一、注冊免費阿里云服務器 1. 進入阿里云服務器官網 阿里云-計算&#xff0c;為了無法計算的價值https://www.aliyun.com/?spm5176.ecscore_server.console-base_top-nav.dlogo.39144df5uvPLOm 2. 點擊免費試用 這里我已經試用過了&#xff0c;大家選擇合適的云服務器點擊立…

如何清理 Docker 占用的巨大磁盤空間

我相信很多人在使用 Docker 一段時間后&#xff0c;都會遇到一個常見問題&#xff1a;磁盤空間被迅速吃光&#xff0c;尤其是在進行頻繁的鏡像構建、測試和運行容器時。以我自己為例&#xff0c;在 Ubuntu 24.04設備上&#xff0c;docker system df -v 一看&#xff0c;Docker …

【CMake】緩存變量

目錄 一. 緩存變量 二.創建緩存變量 2.1.使用set()來創建緩存變量 2.2.使用FORCE參數來覆蓋緩存變量 2.2.1.示例1——不帶force的set是不能覆蓋已經存在的緩存變量的 2.2.2.示例2——帶force的set才能覆蓋已經存在的緩存變量 2.2.3.對比示例 2.3.命令行 -D 創建/覆蓋緩…

vue2使用若依框架動態新增tab頁并存儲之前的tab頁的操作

1. 應用場景&#xff1a;點擊歷史記錄&#xff0c;要比較兩個tab頁的內容時&#xff0c;需要做到切換tab頁來回看左右對數據對比。2.開發難點若依項目正常是把路由配置到菜單管理里&#xff0c;都是設定好的。不過它也給我們寫好了動態新增tab頁的方&#xff0c;需要我們自己來…

論文閱讀-SelectiveStereo

文章目錄1 概述2 模塊2.1 SelectiveIGEV和IGEV的差異2.2 上下文空間注意力2.2.1 通道注意力2.2.2 空間注意力2.3 SRU3 效果參考資料1 概述 本文主要結合代碼對Selective的創新點進行針對性講解&#xff0c;相關的背景知識可以參考我寫的另兩篇文章論文閱讀-RaftStereo和論文閱…

深入分析神馬 M56S+ 202T 礦機參數與性能特點

引言在比特幣&#xff08;BTC&#xff09;和比特幣現金&#xff08;BCH&#xff09;等主流加密貨幣的挖掘過程中&#xff0c;礦機的選擇直接關系到挖礦的效率與收益。神馬 M56S 202T礦機是SHA-256算法的礦機&#xff0c;憑借其強大的算力和高效的能效比&#xff0c;成為了礦工們…

36.2Linux單總線驅動DS18B20實驗(詳細講解代碼)_csdn

想必看過我很多次博客的同學&#xff0c;都知道了編寫驅動的流程&#xff01; 這里我們還是按照以前的習慣來一步一步講解&#xff01; 單總線驅動&#xff0c;在F103和51單片機的裸機開發中是經常見的。 linux驅動代碼編寫實際上就是&#xff0c;端對端的編程&#xff01; 就是…

【雜類】應對 MySQL 處理短時間高并發的請求:緩存預熱

一、什么是緩存預熱&#xff1f;1. 核心概念??緩存預熱&#xff08;Cache Warm-up&#xff09;?? 是指在系統??正式對外提供服務之前??&#xff0c;或??某個高并發場景來臨之前??&#xff0c;??主動??將后續極有可能被訪問的熱點數據從數據庫&#xff08;MySQL…

點評項目(Redis中間件)第三部分短信登錄,查詢緩存

可以直接看后面Redis實現功能的部分基于session實現短信登錄發送短信驗證碼前端請求樣式業務層代碼Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {Overridepublic Result sendCode(String phone, HttpSession se…

線性方程求解器的矩陣分裂

大概思路是對的&#xff0c;但是查老師可能會出現幻覺&#xff0c;小心食用 &#x1f603;這段代碼是在初始化迭代法求解器&#xff0c;構建迭代矩陣和分裂矩陣。以下是詳細解釋&#xff1a; if init_from_func or init_from_input:# 1. 存儲剛度矩陣self.stiff_p stiff_p# 2.…