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

Google 程式設計挑戰賽題目 WordPath 解法:動態規劃計算路徑數

     編輯:關於VC++

2005 年 Google 中國程式設計挑戰賽入圍賽的一道 Hard/Mid 級題目 WordPath。給定字母矩陣 grid 與目標單字 find,從任意起點出發,可向 8 方向(含對角線)移動,格子可重複使用但不可連續停留同一格。求符合條件的路徑總數,超過 1,000,000,000 回傳 -1。

題目範例

GridFind輸出說明
{"ABC","FED","GHI"}"ABCDEFGHI"1唯一路徑,每格用一次
{"ABC","FED","GAI"}"ABCDEA"2E→A 有兩種走法
{"AA","AA"}"AAAA"1084起點 × 3³ 方向選擇
5×5 全 "A"11 個 "A"-1路徑數超過 10 億
{"AB","CD"}"AA"0不可連續停留同格

解題思路:動態規劃 + 位置向量

1. 前處理:記錄每個字元在 Grid 中的所有位置

struct POS { int x, y, count; };
typedef vector VETPOS;

int findStrLen = find.length();
int gridSize = grid.size();
int gridStrLen = grid[0].length();

vector vec(findStrLen);  // vec[k] 存放 find[k] 在 grid 的所有座標

for (int i = 0; i < gridSize; i++)
    for (int j = 0; j < gridStrLen; j++)
        for (int k = 0; k < findStrLen; k++)
            if (find[k] == grid[i][j]) {
                POS ps = {j, i, 1};  // 起始位置 count=1
                vec[k].push_back(ps);
            }

2. 遞推關係:動態規劃計算路徑數

vec[i][j].count 表示「走到 find[i] 這個字元、且位於 grid 某座標」的路徑數。

  • 基底情況:vec[0][*].count = 1(每個起點 1 條路徑)
  • 遞推公式:cur.count = Σ pre[k].count,其中 pre[k] 為上一字元所有可移動到達 cur 位置的座標
  • 可移動判定:兩座標 (x1,y1)、(x2,y2) 滿足 max(|x1-x2|, |y1-y2|) == 1 且不全為 0

3. 核心遞推函式 pathCount

int pathCount(POS& ps, VETPOS& pre) {
    ps.count = 0;
    for (int i = 0; i < pre.size(); i++) {
        int xAbs = abs(ps.x - pre[i].x);
        int yAbs = abs(ps.y - pre[i].y);
        if ((xAbs == 1 && yAbs < 2) || (yAbs == 1 && xAbs < 2)) {
            ps.count += pre[i].count;  // 累加可達路徑數
        }
    }
    return ps.count;
}

4. 主流程:逐字元過濾無效位置並累加


VETPOS midVes;
for (int i = 1; i < findStrLen; i++) {
    midVes.clear();
    for (int j = 0; j < vec[i].size(); j++) {
        POS cur = vec[i][j];
        if (pathCount(cur, vec[i-1]))  // 有可達路徑
            midVes.push_back(cur);
    }
    vec[i].clear();
    if (midVes.empty()) return 0;  // 斷路
    vec[i] = midVes;  // 只保留有效位置
}

// 統計終點總路徑數
int total = 0;
for (int j = 0; j < vec[findStrLen-1].size(); j++) {
    total += vec[findStrLen-1][j].count;
    if (total > 1000000000) return -1;
}
return total;

完整類別實作

class WordPath {
    struct POS { int x, y, count; };
    typedef vector VETPOS;

public:
    int countPaths(vector grid, string find) {
        // ... 完整實作見上方邏輯 ...
    }
private:
    int pathCount(POS& ps, VETPOS& pre) { /* ... */ }
};

複雜度分析

  • 時間:O(|find| × |grid|²) —— 每字元比對前一字元所有位置
  • 空間:O(|find| × |grid|) —— 儲存各字元位置向量
  • Grid 最大 50×50,Find 最大 50,極限情況約 12.5M 次比對,極易在時限內通過

心得與改進方向

  • 參考運籌學動態規劃思想,邊搜尋邊統計,避免列舉所有路徑
  • 若 Grid 行長度不一,將內層迴圈改為 j < grid[i].length() 即可相容
  • 可進一步優化:預計算每個位置的 8 鄰居索引,減少重複座標運算

歡迎大家提出更優解法或指正錯誤!聯繫:txqc4@sohu.com

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