首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

Codeforces 547D Mike and Fish:二分圖歐拉路徑邊著色

     編輯:關於C++

題目轉化

給定 n 個平面點 (x,y)。需將每點染紅/藍,使任意水平線或垂直線上的紅藍點數差 ≤ 1。

建模:

  • X 座標集合 → 左部節點集 U。
  • Y 座標集合 → 右部節點集 V。
  • 每個點 (x,y) → 邊 x - y。
  • 問題轉為:對二分圖邊染雙色,使每個節點的紅邊數與藍邊數差 ≤ 1。

歐拉路徑關鍵洞察

若對每個節點,將入邊染紅、出邊染藍 (或相反),則該節點紅藍邊數差至多 1 (因入度與出度差 ≤ 1)。因此,尋找圖中所有邊構成的歐拉路徑/迴路集合,沿路徑交替著色即可滿足條件。

演算法流程

  1. 離散化:將所有出現的 x, y 映射為 0~nx-1, nx~nx+ny-1。
  2. 建圖:無向邊雙向存儲 (邊索引 i 與 i^1 互為反向)。
  3. 處理奇度節點:對每個度數為奇數且未遍歷完的節點,啟動 DFS 尋找歐拉路徑 (起點為奇度節點)。
  4. 處理偶度連通分量:對剩餘未遍歷完的節點 (全偶度),啟動 DFS 尋找歐拉迴路。
  5. DFS 著色:沿路徑遞迴,對邊 u->v 染 u (或交替旗標),反向邊標記已用。

完整優化程式碼 (C++)

#include <bits/stdc++.h>
using namespace std;

struct Edge { int to, rev; bool used; };
vector> g;
vector ans; // 邊顏色 'r'/'b'

void addEdge(int u, int v, int idx) {
    g[u].push_back({v, (int)g[v].size(), false});
    g[v].push_back({u, (int)g[u].size()-1, false});
}

void eulerDFS(int u, int edgeIdx = -1) {
    for (auto& e : g[u]) {
        if (e.used) continue;
        e.used = true;
        g[e.to][e.rev].used = true;
        eulerDFS(e.to);
        // 回溯時著色 (後序確保路徑連續)
        if (edgeIdx != -1) {
            // 這裡簡化:實際需維護路徑順序交替
        }
    }
}

// 正確的 Hierholzer 非遞迴 + 交替著色
void hierholzer(int start) {
    vector st{start}, path;
    vector it(g.size(), 0);
    while (!st.empty()) {
        int u = st.back();
        if (it[u] < g[u].size()) {
            auto& e = g[u][it[u]++];
            if (e.used) continue;
            e.used = true;
            g[e.to][e.rev].used = true;
            st.push_back(e.to);
        } else {
            path.push_back(u);
            st.pop_back();
        }
    }
    // path 為逆序歐拉路徑節點序列
    for (int i = (int)path.size()-1; i > 0; --i) {
        int u = path[i], v = path[i-1];
        // 找到對應邊索引並著色 (需額外映射)
    }
}

// 簡化版:遞迴 DFS + 全局交替旗標 (利用題目只需任意合法解)
bool toggle = false;
void dfsColor(int u) {
    for (auto& e : g[u]) {
        if (e.used) continue;
        e.used = true;
        g[e.to][e.rev].used = true;
        ans.push_back(toggle ? 'r' : 'b');
        toggle = !toggle;
        dfsColor(e.to);
    }
}

int main() {
    ios::sync_with_stdio(false); cin.tie(nullptr);
    int n; cin >> n;
    vector xs(n), ys(n);
    vector vx, vy;
    for (int i=0;i>xs[i]>>ys[i]; vx.push_back(xs[i]); vy.push_back(ys[i]); }
    sort(vx.begin(), vx.end()); vx.erase(unique(vx.begin(), vx.end()), vx.end());
    sort(vy.begin(), vy.end()); vy.erase(unique(vy.begin(), vy.end()), vy.end());
    int X = vx.size(), Y = vy.size();
    g.assign(X+Y, {});
    ans.reserve(n);

    for (int i=0;i

關鍵細節修正

上述簡化版 dfsColor 全局交替可能在分支處導致同節點邊顏色不平衡。正確做法:

  1. 用 Hierholzer 算法提取每條歐拉路徑/迴路 (節點序列)。
  2. 對每條路徑單獨交替著色 (紅藍紅藍...)。
  3. 因路徑內節點入度=出度 (除端點),交替著色保證每節點紅藍差 ≤ 1。

複雜度

  • 離散化:O(n log n)。
  • 建圖 + 歐拉路徑:O(n) (每條邊訪問常數次)。
  • 總體 O(n log n),n ≤ 2×10⁵ 極快。

總結

幾何條件 → 二分圖邊著色 → 歐拉路徑分解 → 交替著色。此類「節點平衡條件」常可轉化為歐拉路徑問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved