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

HDU 1045 Fire Net:基於 DFS 回溯的最大獨立集求解

     編輯:關於C語言

問題建模

N×N 棋盤,部分格子為牆 (X),在空格 (.) 放置碉堡,要求**同行同列無牆阻隔的兩碉堡不可相見**。求最大放置數。本質是**一般圖的最大獨立集** (NP-Hard),但 N≤4 且牆壁將棋盤分割為小區域,回溯可行。

核心觀察:行列獨立性

牆壁將行/列分割成段。同一段內最多放 1 個碉堡。可視為:每個空格屬於一個「行段」和一個「列段」,選擇格子等價於選擇行段-列段配對,**雙圖最大匹配**模型。但 N 小,直接 DFS 回溯更簡單。

DFS 回溯算法

狀態表示

  • row[i]:第 i 行當前段是否已放碉堡
  • col[j]:第 j 列當前段是否已放碉堡
  • used[i][j]:當前格子是否在本路徑被佔用

關鍵剪枝:遇牆重置行列狀態

void dfs(int cnt) {
    ans = max(ans, cnt);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (board[i][j] == '.' && !used[i][j] && !row[i] && !col[j]) {
                used[i][j] = row[i] = col[j] = 1;
                dfs(cnt + 1);
                used[i][j] = row[i] = col[j] = 0;
            }
            else if (board[i][j] == 'X') {  // 關鍵:牆壁阻隔,重置行列段狀態
                row[i] = col[j] = 0;
            }
        }
    }
}

**牆壁重置** 是核心:同一行遇到牆,之前段的佔用狀態失效,新段重新計算。

完整 Java 實現

import java.util.Scanner;

public class HDU1045 {
    static char[][] board;
    static boolean[][] used;
    static int[] row, col;
    static int n, ans;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            n = sc.nextInt();
            if (n == 0) break;
            board = new char[n][n];
            used = new boolean[n][n];
            row = new int[n];
            col = new int[n];
            ans = 0;
            for (int i = 0; i < n; i++) {
                String s = sc.next();
                for (int j = 0; j < n; j++) board[i][j] = s.charAt(j);
            }
            dfs(0);
            System.out.println(ans);
        }
    }

    static void dfs(int cnt) {
        if (cnt > ans) ans = cnt;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (board[i][j] == '.' && !used[i][j] && row[i] == 0 && col[j] == 0) {
                    used[i][j] = true; row[i] = 1; col[j] = 1;
                    dfs(cnt + 1);
                    used[i][j] = false; row[i] = 0; col[j] = 0;
                } else if (board[i][j] == 'X') {
                    row[i] = 0; col[j] = 0;  // 牆壁重置
                }
            }
        }
    }
}

優化方向:雙圖最大匹配 (霍普克羅夫特-卡普算法)

  1. 掃描棋盤,分配行段 ID 和列段 ID
  2. 每個空格連接其行段和列段
  3. 二分圖最大匹配 = 最大碉堡數 (Kőnig 定理)
  4. 時間 O(E√V),N=100 也能秒殺

複雜度分析

  • 回溯:最址 O(4^(N²)),但 N≤4 且牆壁剪枝極強,實測 < 10ms
  • 最大匹配:O(N² √N²) = O(N^2.5),通用解法

總結

HDU 1045 看似 NP-Hard,實則利用 **N≤4 且牆壁分割** 特性,簡單 DFS 回溯 + **牆壁重置行列狀態** 即可 AC。理解「行段/列段」概念,能舉一反三解決「放國王」、「放車」、「電路佈線」等棋盤約束問題。進階學習 **二分圖最大匹配**,將棋盤問題統一建模為圖論模型。

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