【圖論】分層圖

一、分層圖的核心思想

分層圖是一種將圖的不同狀態拆分為多個“層”的建模方法,每層對應一種特定狀態。通過這種方式,可以將復雜的狀態轉移問題轉化為多層圖中的最短路徑問題。

核心特點

  • 層內邊:表示普通操作(如正常行走)。
  • 層間邊:表示狀態轉移(如使用一次特殊能力、改變狀態等)。
  • 狀態壓縮:通常通過 j * n + u 的方式編號節點(j 表示層數,u 是原圖節點)。

二、分層圖的構建方法

  1. 物理構圖

    • 定義:直接將圖復制為 k 層,每層節點數為 n
    • 層內邊:與原圖相同,邊權不變。
    • 層間邊:按狀態轉移規則添加(如使用一次特殊能力)。
    • 適用場景k 較小(如 k ≤ 10)。
    • 缺點:空間消耗大(總節點數為 k * n)。
  2. DP 構圖

    • 定義:通過動態規劃模擬狀態轉移,無需顯式構建多層圖。
    • 狀態表示:使用二維數組 dis[u][j] 表示在節點 u、狀態 j 下的最短距離。
    • 適用場景:狀態維度較大的問題(如時間、鑰匙狀態等)。
    • 優點:節省空間,適合高維狀態。

三、分層圖的典型應用場景

  1. 有限次決策

    • 例題:允許最多使用 k 次特殊能力(如免費邊、升級等)。
    • 建模:構建 k+1 層圖,層間邊表示使用能力。
  2. 狀態依賴

    • 例題:鑰匙狀態、時間余數、奇偶性等。
    • 建模:根據狀態分層(如鑰匙狀態用二進制編碼)。
  3. 多維狀態轉移

    • 例題:同時考慮時間、資源、權限等狀態。
    • 建模:每個維度對應一層,組合成多維分層圖。

四、分層圖的詳細例題與實現

例題 1:JLOI2011 飛行路線(允許 k 次免費邊)

問題描述
給定一個無向圖,最多可以選擇 k 條邊免費,求從起點到終點的最短路徑。

分層圖建模

  • 構建 k+1 層圖(0~k 層)。
  • 層內邊:原圖邊權不變。
  • 層間邊:從第 j 層的 u 到第 j+1 層的 v,邊權為 0(表示使用一次免費機會)。

C++ 實現

#include <bits/stdc++.h>
using namespace std;const int N = 1e5 + 10, M = 1e6 + 10;
int h[N * 10], e[M * 2], ne[M * 2], w[M * 2], idx;
bool st[N * 10];
int dis[N * 10];void add(int a, int b, int c) {e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}void dijkstra(int n, int k) {priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;memset(dis, 0x3f, sizeof dis);dis[1] = 0;pq.push({0, 1});while (pq.size()) {auto [d, u] = pq.top();pq.pop();if (st[u]) continue;st[u] = true;for (int i = h[u]; ~i; i = ne[i]) {int v = e[i], cost = w[i];if (dis[v] > d + cost) {dis[v] = d + cost;pq.push({dis[v], v});}}}
}int main() {int n, m, k;cin >> n >> m >> k;memset(h, -1, sizeof h);for (int i = 0; i < m; i++) {int a, b, c;cin >> a >> b >> c;for (int j = 0; j <= k; j++) {int u = a + j * n, v = b + j * n;add(u, v, c), add(v, u, c); // 層內邊if (j < k) {int u2 = a + (j + 1) * n, v2 = b + (j + 1) * n;add(u, v2, 0), add(v, u2, 0); // 層間免費邊add(v, v2, 0), add(u, u2, 0);}}}dijkstra(n, k);int res = 0x3f3f3f3f;for (int j = 0; j <= k; j++) {res = min(res, dis[n + j * n]);}cout << res << endl;return 0;
}

關鍵點

  • 節點編號u + j * n 表示第 j 層的節點 u
  • 層間邊:允許最多 k 次免費升級,邊權為 0。

例題 2:CSP-J 2023 旅游巴士(時間余數分層)

問題描述
給定發車間隔 k,求從起點到終點的最短時間(允許等待多輪車次)。

分層圖建模

  • 按時間余數 t % k 分層,共 k 層。
  • 狀態 (u, t % k):表示當前在節點 u,時間余數為 t % k
  • 邊權動態調整:根據當前時間和發車間隔 k 計算等待時間。

C++ 實現

#include <bits/stdc++.h>
using namespace std;const int N = 1e5 + 10, K = 1e3 + 10;
int h[N], e[N * 2], ne[N * 2], w[N * 2], idx;
int dis[N][K]; // dis[u][j]: 節點u,余數j的最短時間void add(int a, int b, int c) {e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}void dijkstra(int n, int k) {priority_queue<tuple<int, int, int>, vector<tuple<int, int, int>>, greater<>> pq;memset(dis, 0x3f, sizeof dis);dis[1][0] = 0;pq.push({0, 1, 0});while (!pq.empty()) {auto [d, u, t_mod] = pq.top();pq.pop();if (d > dis[u][t_mod]) continue;for (int i = h[u]; ~i; i = ne[i]) {int v = e[i], cost = w[i];int current_time = d;if (current_time < cost) {// 需要等待int delta = ((cost - current_time + k - 1) / k) * k;int new_time = current_time + delta;int new_mod = new_time % k;if (dis[v][new_mod] > new_time) {dis[v][new_mod] = new_time;pq.push({new_time, v, new_mod});}} else {// 直接走int new_time = current_time + 1;int new_mod = new_time % k;if (dis[v][new_mod] > new_time) {dis[v][new_mod] = new_time;pq.push({new_time, v, new_mod});}}}}
}int main() {int n, m, k;cin >> n >> m >> k;memset(h, -1, sizeof h);for (int i = 0; i < m; i++) {int a, b, c;cin >> a >> b >> c;add(a, b, c), add(b, a, c);}dijkstra(n, k);int res = 0x3f3f3f3f;for (int j = 0; j < k; j++) {res = min(res, dis[n][j]);}cout << res << endl;return 0;
}

關鍵點

  • 狀態壓縮dis[u][j] 表示節點 u 在余數 j 下的最短時間。
  • 動態調整時間:根據當前時間和發車間隔 k 計算等待時間。

五、分層圖的擴展應用

例題 3:孤島營救問題(鑰匙狀態分層)

問題描述
網格圖中,門需要鑰匙開啟,鑰匙分布在格子中,求從起點到終點的最短路徑。

分層圖建模

  • 鑰匙狀態:用二進制表示鑰匙狀態(如 101 表示有鑰匙 1 和 3)。
  • 層內邊:普通移動(墻或門未解鎖時無法通過)。
  • 層間邊:拾取鑰匙后狀態轉移。

C++ 實現(邏輯構圖):

#include <bits/stdc++.h>
using namespace std;const int N = 11, M = 100;
int h[M], e[M], ne[M], w[M], idx;
int dis[M][1 << 10]; // dis[u][state]: 節點u,鑰匙狀態state的最短距離void add(int a, int b, int c) {e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}void bfs(int n, int m, int p) {queue<pair<int, int>> q;memset(dis, 0x3f, sizeof dis);dis[0][0] = 0; // 起點(0,0),無鑰匙q.push({0, 0});while (!q.empty()) {auto [u, state] = q.front();q.pop();for (int i = h[u]; ~i; i = ne[i]) {int v = e[i], cost = w[i];int new_state = state;// 檢查是否需要鑰匙if (需要鑰匙) {if (state 有鑰匙) {new_state = state | 鑰匙狀態;} else {continue; // 無法通過}}if (dis[v][new_state] > dis[u][state] + cost) {dis[v][new_state] = dis[u][state] + cost;q.push({v, new_state});}}}
}

六、分層圖的優化技巧

  1. 空間優化

    • 物理構圖:總節點數為 k * n,邊數為 k * m + ...
    • DP 構圖:狀態數為 n * 2^pp 為鑰匙種類數)。
  2. 時間優化

    • 使用 01BFS(邊權為 0 或 1 時)。
    • 使用 優先隊列優化的 Dijkstra(邊權任意值)。
  3. 狀態壓縮

    • 對于鑰匙狀態,用二進制位壓縮。
    • 對于時間余數,用 t % k 表示。

七、分層圖的適用場景總結

場景類型示例問題分層依據構圖方式
有限次決策免費邊、升級使用次數物理構圖
狀態依賴鑰匙、時間余數鑰匙狀態、余數DP 構圖
多維狀態轉移資源、權限組合狀態DP 構圖

八、分層圖的常見錯誤與調試

  1. 節點編號錯誤:確保 u + j * n 正確映射層和節點。
  2. 層間邊方向錯誤:層間邊應單向(如從 j 層到 j+1 層)。
  3. 初始化錯誤dis 數組未初始化為最大值。
  4. 優先隊列優先級錯誤:使用 greater<> 保證最小堆。

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

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

相關文章

當穩定幣開始生息:USDT0 與 Berachain 的二次進化故事

如果說過去幾年&#xff0c;穩定幣是 DeFi 世界里最安穩的一塊基石&#xff0c;那么 2025 年的 Berachain 正在把它們重新塑造成一種新的資產類型。在這條新興的公鏈上&#xff0c;穩定幣不再只是 “資金的搬運工”&#xff0c;而是搖身一變&#xff0c;成為能生息、能博弈、能…

Kafka、RabbitMQ 與 RocketMQ 在高并發場景下的高可用與性能對比分析

Kafka、RabbitMQ 與 RocketMQ 在高并發場景下的高可用與性能對比分析 消息隊列作為分布式系統中常見的異步解耦組件&#xff0c;在高并發場景下對可用性和性能提出了極高的要求。本文基于生產環境需求&#xff0c;深入分析 Kafka、RabbitMQ 與 RocketMQ 三大主流消息中間件在高…

深入理解 HTTP 與 HTTPS:區別以及 HTTPS 加密原理

目錄 一、HTTP 與 HTTPS 的基本概念 二、HTTP 與 HTTPS 的核心區別 三、為什么需要 HTTPS&#xff1f; 四、HTTPS 的加密通信原理&#xff08;核心&#xff09; 1. 客戶端發起 HTTPS 請求 2. 服務端返回 SSL/TLS 證書 3. 客戶端驗證證書 4. 客戶端生成對稱密鑰并用公鑰…

零售行業的 AI 革命:從用戶畫像到智能供應鏈,如何讓 “精準營銷” 不再是口號?

AI 浪潮下的零售變革?在科技飛速發展的今天&#xff0c;人工智能&#xff08;AI&#xff09;正以前所未有的態勢席卷全球&#xff0c;深刻地改變著各行各業的運營模式和發展軌跡&#xff0c;零售行業自然也難以置身事外。AI 技術憑借其強大的數據處理能力、精準的分析預測能力…

PyTorch 面試題及詳細答案120題(96-105)-- 性能優化與調試

《前后端面試題》專欄集合了前后端各個知識模塊的面試題,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,SQL,Linux… 。 前后端面試題-專欄總目錄 文章目錄 一、本文面試題目錄 96. 如何查看PyTorch模型的…

Linux 孤兒進程 (Orphan Process)

&#x1f381;個人主頁&#xff1a;工藤新一 &#x1f50d;系列專欄&#xff1a;C面向對象&#xff08;類和對象篇&#xff09; &#x1f31f;心中的天空之城&#xff0c;終會照亮我前方的路 &#x1f389;歡迎大家點贊&#x1f44d;評論&#x1f4dd;收藏?文章 文章目錄孤…

Linux Tun/Tap 多隊列技術

&#x1f525; Linux Tun/Tap 多隊列技術 引用&#xff1a;Linux tun/tap 驅動多隊列模式&#xff08;C/C&#xff09; &#x1f4d6; 引言 Tun/Tap 是 Linux 內核提供的虛擬網絡設備&#xff0c;廣泛應用于 VPN、虛擬化、網絡隧道等領域。傳統單隊列模式在高吞吐量場景下存…

docker 啟動一個clickhouse , docker 創建ck數據庫

1. 拉鏡像&#xff1a;docker pull clickhouse/clickhouse-server2. 創建容器并且啟動命令&#xff1a;docker run -d --name clickhouse-server \-p 8123:8123 -p 9000:9000 \clickhouse/clickhouse-server3. 日志文件的映射&#xff0c;可以自己配置下&#xff0c;目前創建的…

合約服務架構-OOP 方式

文章目錄前言&#x1f3af; 經典的面向對象編程&#xff01;1. &#x1f3d7;? **封裝 (Encapsulation)**2. &#x1f9ec; **繼承 (Inheritance)**3. &#x1f3ad; **多態 (Polymorphism)**4. &#x1f3a8; **抽象 (Abstraction)**&#x1f3db;? 設計模式的應用1. **工廠…

C# 生成器模式(一個投資跟蹤程序)

一個投資跟蹤程序 我們考慮一個稍微簡單一點的例子&#xff0c;在這個例子中&#xff0c;用一個類構造一個用戶界面。假設我 們要編寫一個程序來跟蹤投資的效益。我們有股票、債券和基金等投資項目&#xff0c;對每一種投資項 目都要顯示持有量的列表&#xff0c;這樣就能夠選擇…

【DBCExcelConvent】CAN報文解析輔助工具之DBC與Excel互轉

前言 CAN總線翻譯文件DBC是整車解析過程中非常核心的一部分&#xff0c;因此為了能被各大CAN工具解析&#xff0c;它也有自己的一套編碼規則。但并不是無時無刻都有條件打開該文件&#xff0c;對于工程師而言。其實比較直觀和通用的大多數還是Excel表格。因此&#xff0c;為了打…

如何將iPhone日歷傳輸到電腦

iPhone日歷是i設備上一個非常出色的內置應用程序&#xff0c;可以幫助你創建、查看和管理日程或事件。對于所有iPhone用戶來說&#xff0c;在iPhone日歷上添加新事件非常容易。然而&#xff0c;當涉及到將日歷從iPhone傳輸到電腦時&#xff0c;許多人可能會感到困惑&#xff0c…

TDengine 3.3.7.0 新增性能基準工具 taosgen

taosgen 工具參考手冊 taosgen 是時序數據領域產品的性能基準測試工具&#xff0c;支持數據生成、寫入性能測試等功能。taosgen 以“作業”為基礎單元&#xff0c;作業是由用戶定義&#xff0c;用于完成特定任務的一組操作集合。每個作業包含一個或多個步驟&#xff0c;并可通…

模式組合應用-組合模式

寫在前面Hello&#xff0c;我是易元&#xff0c;這篇文章是我學習設計模式時的筆記和心得體會。如果其中有錯誤&#xff0c;歡迎大家留言指正&#xff01; 本文為設計模式間的組合使用&#xff0c;涉及代碼較多&#xff0c;個人覺得熟能生巧&#xff0c;希望自己能從中學習到新…

在Ubuntu中安裝配置MySql Server

1.安裝MySql Server在命令行控制臺執行安裝命令&#xff1a;sudo apt install mysql-server安裝完成后&#xff0c;因為沒有root用戶的密碼&#xff0c;所以&#xff0c;登錄不了mysql的cli。另外&#xff0c;MySql 8以上&#xff0c;lower-case-table-names默認值0&#xff0c…

Docker 40個自動化管理腳本-1 (20/40)

文章目錄1. 自動化容器創建腳本2. 批量啟動所有容器3. 批量停止運行中容器#!/bin/bash4. 批量刪除停止的容器5. 運行容器并在退出后自動清理6. 自動重啟關鍵容器7. 容器資源監控腳本8. 監控所有容器資源使用9. 檢查所有容器日志10. 清理未使用資源腳本11. 刪除懸空鏡像12. 容器…

Go學習1:常量、變量的命名

golang 安裝 | go-zero Documentation 在這個文檔里&#xff0c;環境變量系統自動配好了&#xff08;自定義的一樣&#xff09;不需要修改環境變量。 我下載的是1.25版本的。 目前使用go mod管理項目。 C的產出比太低&#xff0c;而Java和C#哲學又來源于C。 Go語言成功的項目…

2025_WSL2_Ubuntu20.04_C++20_concept 環境配置

需要使用 c20 新特性 concept 泛型約束 記錄如何在 wsl2 里面配置環境&#xff0c;如果需要源工程&#xff0c;可以私發 背景&#xff1a;使用 CMakeLists.txt 配置整個工程 從官網 https://gcc.gnu.org/projects/cxx-status.html#cxx20 可以看到 concept 受 g10 支持這里注意雖…

Encoder編碼器

Encoder編碼器 #include <libavutil/log.h> #include <libavutil/opt.h> #include <libavcodec/avcodec.h>static int encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt, FILE *out){int ret -1;ret avcodec_send_frame(ctx, frame);if(ret <…

微服務-ruoyi-cloud部署

微服務 阿里 阿里nacos 注冊中心&#xff0c;配置中心 spring cloud gateway網關 公共服務 阿里sentinel 面向分布式、多語言異構化服務架構的流量治理組件 阿里seata 是一款開源的分布式事務解決方案 nginx 靜態資源服器 反向代理 ruoyi-cloud部署架構 VM配置 網…