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

HDU 1150 Machine Schedule:二分圖最小點覆蓋與最大匹配

     編輯:C++ 入門

問題描述

HDU 1150 要求找出二分圖的最小點覆蓋數。根據Kőnig 定理:

二分圖的最小點覆蓋數 = 最大匹配數

因此問題轉化為求二分圖最大匹配。

演算法:匈牙利算法

使用 DFS 基礎的匈牙利算法尋找增廣路徑,時間複雜度 O(VE),適用於本題資料範圍。

Java 完整解法

import java.io.*;
import java.util.*;

class Edge {
    int to, next;
}

class Solution {
    static Scanner in = new Scanner(System.in);
    static PrintWriter out = new PrintWriter(System.out);
    
    int n, m;                    // 兩邊頂點數
    int[] match = new int[1111]; // 右側頂點匹配的左側頂點
    Edge[] edges = new Edge[1111];
    int[] head = new int[1111];
    int[] vis = new int[1111];
    int tot = 0;
    
    void init() {
        tot = 0;
        Arrays.fill(match, -1);
        Arrays.fill(head, -1);
    }
    
    void addEdge(int u, int v) {
        edges[tot] = new Edge();
        edges[tot].to = v;
        edges[tot].next = head[u];
        head[u] = tot++;
    }
    
    // DFS 尋找增廣路徑
    boolean dfs(int u) {
        for (int i = head[u]; i != -1; i = edges[i].next) {
            int v = edges[i].to;
            if (vis[v] == 1) continue;
            vis[v] = 1;
            if (match[v] == -1 || dfs(match[v])) {
                match[v] = u;
                return true;
            }
        }
        return false;
    }
    
    void solve() {
        while (in.hasNext()) {
            init();
            n = in.nextInt();
            if (n == 0) break;
            m = in.nextInt();
            int k = in.nextInt();
            
            for (int i = 1; i <= k; i++) {
                int a = in.nextInt(); // 機器編號(忽略)
                int b = in.nextInt(); // 左側頂點
                int c = in.nextInt(); // 右側頂點
                addEdge(b, c);
            }
            
            int ans = 0;
            for (int i = 1; i <= n; i++) {
                Arrays.fill(vis, 0);
                if (dfs(i)) ans++;
            }
            out.println(ans);
        }
        out.close();
    }
}

public class Main {
    public static void main(String[] args) {
        new Solution().solve();
    }
}

核心邏輯解析

1. 圖的建模

  • 左側集合:機器 A(1~n)
  • 右側集合:機器 B(1~m)
  • 邊:可相容的機器對

2. 匈牙利算法流程

  1. 對每個左側未匹配頂點,嘗試尋找增廣路徑
  2. DFS 遍歷鄰接邊,若右側頂點未被訪問:
  3.  若右側未匹配,直接匹配
  4.  若右側已匹配,遞迴嘗試為其原匹配左側頂點尋找新匹配
  5. 找到增廣路徑則匹配數 +1

3. 關鍵資料結構

陣列用途
head[]鄰接表頭指標
edges[]邊資訊(終點、下一條邊索引)
match[]右側頂點對應的左側匹配頂點
vis[]DFS 當輪訪問標記

複雜度分析

  • 時間:O(n × k) ≈ O(VE),n ≤ 100,k ≤ 1000,極快
  • 空間:O(V + E)

常見錯誤與注意點

  1. 訪問標記重置:每次 DFS 前必須 Arrays.fill(vis, 0)
  2. 多組測試資料:while (in.hasNext()) 迴圈處理,遇到 n=0 結束
  3. 輸入格式:每條邊輸入三個數 a b c,其中 a 為機器編號(題目背景資訊,解題時忽略)

擴展:HK 算法優化

若資料範圍擴大(V ~ 10⁵),可改用 Hopcroft-Karp 算法,時間複雜度 O(√V × E),利用 BFS 分層 + DFS 尋找多條最短增廣路徑並行推進。

總結

HDU 1150 是二分圖最大匹配的經典應用。掌握 Kőnig 定理與匈牙利算法 DFS 實作,是解決此類問題的核心技能。Java 實作需注意輸入輸出效率,使用 Scanner + PrintWriter 並關閉緩衝區足以應對本題規模。

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