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

FZU 2186 小明的迷宮:狀態壓縮 DP + BFS

     編輯:關於C++

問題描述

N×M 迷宮,起點 (1,1),有若干寶藏(≤10)。求從起點出發收集所有寶藏的最短路徑長度。可上下左右移動,不可穿牆。若無法收集全輸出 -1,若起點即為寶藏且無其他寶藏輸出 0。

解題思路

  1. 提取所有關鍵點:起點 + 所有寶藏,編號 0..K。
  2. 對每個關鍵點 BFS 計算到其他關鍵點的最短距離,構建距離矩陣 dist[i][j]。若任意兩關鍵點不可達,輸出 -1。
  3. 狀態壓縮 DP:dp[mask][i] 表示已收集寶藏集合為 mask,當前位於關鍵點 i 的最短路徑。初始 dp[1][0] = 0(起點編號 0,mask 第 0 位為 1)。轉移:dp[mask | (1<。
  4. 答案為 min_i dp[(1<<(K+1))-1][i]。

代碼實現 (C++)

#include 
using namespace std;
const int MAXN = 105;
const int INF = 0x3f3f3f3f;
int N, M, grid[MAXN][MAXN];
int dx[4] = {-1,0,1,0}, dy[4] = {0,1,0,-1};
struct Point { int x, y; } poi[15];
int K; // 寶藏數
int dist[15][15];
int dp[1<<12][12];

int bfs(int s, int t) {
    queue> q;
    vector> vis(N+1, vector(M+1, false));
    q.emplace(poi[s].x, poi[s].y, 0);
    vis[poi[s].x][poi[s].y] = true;
    while (!q.empty()) {
        auto [x, y, d] = q.front(); q.pop();
        if (x == poi[t].x && y == poi[t].y) return d;
        for (int i = 0; i < 4; ++i) {
            int nx = x + dx[i], ny = y + dy[i];
            if (nx < 1 || nx > N || ny < 1 || ny > M) continue;
            if (grid[nx][ny] < 0 || vis[nx][ny]) continue;
            vis[nx][ny] = true;
            q.emplace(nx, ny, d+1);
        }
    }
    return -1;
}

int main() {
    while (cin >> N >> M) {
        for (int i = 1; i <= N; ++i)
            for (int j = 1; j <= M; ++j)
                cin >> grid[i][j];
        K = 0;
        for (int i = 1; i <= N; ++i)
            for (int j = 1; j <= M; ++j)
                if (grid[i][j] > 0) poi[++K] = {i, j};
        if (K == 0) { cout << 0 << endl; continue; }
        poi[0] = {1, 1};
        if (grid[1][1] < 0) { cout << -1 << endl; continue; }
        bool ok = true;
        for (int i = 0; i <= K; ++i)
            for (int j = 0; j < i; ++j) {
                dist[i][j] = dist[j][i] = bfs(i, j);
                if (dist[i][j] == -1) ok = false;
            }
        if (!ok) { cout << -1 << endl; continue; }
        int ALL = (1 << (K+1)) - 1;
        memset(dp, 0x3f, sizeof(dp));
        dp[1][0] = 0;
        for (int mask = 0; mask <= ALL; ++mask) {
            for (int i = 0; i <= K; ++i) if (dp[mask][i] < INF) {
                for (int j = 0; j <= K; ++j) if (!(mask & (1<

複雜度分析

  • BFS:O((K+1) * N * M),K ≤ 10。
  • DP:O(2^K * K^2),K ≤ 10 即 1024 * 100 ≈ 10^5。
  • 總體輕鬆通過。

總結

經典的「多目標最短路徑」問題,BFS 求點對距離 + 狀態壓縮 DP 解 TSP 變體。注意起點處理與不可達判斷。

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