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

HDU 4753 九宮格遊戲:狀態壓縮 DP + 記憶化搜索解博弈問題

     編輯:關於C++

遊戲規則

3×3 點陣(9 個格子,24 條邊)。兩人輪流加邊,加邊後若形成新的 1×1 正方形(四條邊全有),得相應分數(1 或 2 分)。已走 n 步,Tom 先手,雙方最優策略,問誰贏。

狀態壓縮設計

  • 24 條邊 → 24 位狀態,但 2^24 太大。
  • 觀察:已走邊 ≥ 12,剩餘 ≤ 12 條 → 僅壓縮未走邊,狀態數 ≤ 2^12 = 4096。
  • 預處理 9 個格子各自的 4 條邊編號 circle[9][4]。

記憶化搜索函數

dfs(state, remaining_squares) 返回當前玩家在狀態 state 下(剩餘 remaining_squares 個可完成格子)的淨得分優勢(當前玩家得分 - 對手得分)。

int dfs(int state, int rem) {
    if (dp[state] != -1) return dp[state];
    if (rem == 0) return dp[state] = 0;
    
    int best = -INF;
    for (int i = 0; i < cnt; ++i) if (state & (1<

關鍵細節

  1. check_gain:檢查加邊後,有多少格子的 4 條邊全滿。需將「已走邊」與「當前嘗試邊」合併判斷。
  2. 初始狀態構建:輸入 n 步,標記已走邊,計算雙方已得分 tom, jerry,剩餘可得分格子數 s。
  3. 最終判斷:若 n 為偶數(輪到 Tom),Tom 總分 = tom + dfs(0, s);Jerry 總分 = jerry + s - dfs(0, s)。比較大小輸出勝者。

完整流程

// 初始化邊編號映射 mp[u][v] = id (1~24)
void init() {
    mp[1][2]=1; mp[2][3]=2; mp[3][4]=3;
    mp[1][5]=4; mp[2][6]=5; mp[3][7]=6; mp[4][8]=7;
    mp[5][6]=8; mp[6][7]=9; mp[7][8]=10;
    mp[5][9]=11; mp[6][10]=12; mp[7][11]=13; mp[8][12]=14;
    mp[9][10]=15; mp[10][11]=16; mp[11][12]=17;
    mp[9][13]=18; mp[10][14]=19; mp[11][15]=20; mp[12][16]=21;
    mp[13][14]=22; mp[14][15]=23; mp[15][16]=24;
    // 9格子邊
    circle[0]={1,4,5,8}; circle[1]={2,5,6,9}; ...
}

int main() {
    init();
    int T; scanf("%d",&T);
    for (int cs=1; cs<=T; ++cs) {
        memset(vis,0,sizeof(vis));
        int n; scanf("%d",&n);
        tom=jerry=0; int prev_sq=0;
        for (int i=0;iy) swap(x,y);
            vis[mp[x][y]]=1;
            int cur_sq = count_squares(); // 掃描9格子
            if (i&1) jerry += cur_sq - prev_sq;
            else tom += cur_sq - prev_sq;
            prev_sq = cur_sq;
        }
        // 收集未走邊
        cnt=0;
        for (int i=1;i<=24;++i) if (!vis[i]) unvis[++cnt]=i;
        int rem = 9 - prev_sq;
        memset(dp,-1,sizeof(dp));
        int diff = dfs(0, rem); // 狀態0表示未走邊全在
        printf("Case #%d: %s\n", cs, 
            (n%2==0 ? (tom+diff > jerry+rem-diff) : (tom+rem-diff > jerry+diff)) 
            ? "Tom200" : "Jerry404");
    }
    return 0;
}

複雜度

  • 狀態數 ≤ 4096,每狀態枚舉 ≤ 12 條邊,總轉移 < 5萬,極快。
  • 記憶化避免重複計算,DFS 深度 ≤ 12。

總結

HDU 4753 是狀態壓縮 DP 解組合博弈的經典案例。關鍵技巧:

  1. 壓縮「未走邊」而非「已走邊」,利用題目約束(剩餘 ≤ 12)壓縮狀態空間。
  2. DP 定義為「當前玩家淨優勢」,轉移公式 max(gained - dfs(next)) 自然體現雙方最優博弈。
  3. 預處理格子-邊映射與得分檢查,將幾何規則轉化為位運算判斷。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved