[980].不同路徑 III

不同路徑 III

 


題目

在二維網格 grid 上,有 4 種類型的方格:

  • 1 表示起始方格。且只有一個起始方格。
  • 2 表示結束方格,且只有一個結束方格。
  • 0 表示我們可以走過的空方格。
  • -1 表示我們無法跨越的障礙。

返回在四個方向(上、下、左、右)上行走時,從起始方格到結束方格的不同路徑的數目,每一個無障礙方格都要通過一次。

示例 1:

輸入:[[1,0,0,0],[0,0,0,0],[0,0,2,-1]]
輸出:2
解釋:我們有以下兩條路徑:
1. (0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2)
2. (0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,2),(2,2)

示例 2:

輸入:[[1,0,0,0],[0,0,0,0],[0,0,0,2]]
輸出:4
解釋:我們有以下四條路徑: 
1. (0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2),(2,3)
2. (0,0),(0,1),(1,1),(1,0),(2,0),(2,1),(2,2),(1,2),(0,2),(0,3),(1,3),(2,3)
3. (0,0),(1,0),(2,0),(2,1),(2,2),(1,2),(1,1),(0,1),(0,2),(0,3),(1,3),(2,3)
4. (0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,2),(2,2),(2,3)

示例 3:

輸入:[[0,1],[2,0]]
輸出:0
解釋:
沒有一條路能完全穿過每一個空的方格一次。
請注意,起始和結束方格可以位於網格中的任意位置。

 


函數原型

int uniquePathsIII(int** grid, int gridSize, int* gridColSize){}
  • grid:二維數組
  • gridSize:二維數組的行數
  • gridColSize:二維數組的列數,但是 int*,所以取值的時候用 *gridColSize
     

邊界判斷

int uniquePathsIII(int** grid, int gridSize, int* gridColSize){
	if( grid == NULL || gridSize == 0 || gridColSize == NULL || *gridColSize == 0 )
		return 0;
}

 


算法設計:DFS回溯哈密爾頓路徑

思路:這道題就是求【哈密爾頓路徑】。

哈密爾頓路徑:從某個點出發,經過每個頂點一次,且恰好每個頂點都只經過一次。

如旅行時,從入口出發如何不重複的走完所有景點,哈密爾頓路徑就是求這個,只不過這個問題不是求【哈密爾頓路徑】是哪條,而是有幾條。

目前求解哈密爾頓路徑沒啥好的算法,所以只能枚舉了。

int dirs[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
int visited[20][20] = {0};

// 判斷頂點(x, y)座標是否越界
bool inArea(int x, int y, int R, int C){     
	return x >= 0 && x < R && y >= 0 && y < C;
}

int DFS(int start, int end, int cnt, int R, int C, int **grid){
    /* 一維轉二維 */
    int x = start / C;
    int y = start % C;
    visited[x][y] = 1;      				 // 起點已訪問
    cnt --;                 				 // 可訪問的點 -1

    if( cnt == 0 && start == end ){
        visited[x][y] = 0;      			 // 回溯清除標記,爲尋找下一條路作準備
        return 1;
    }
    
    int ans = 0;
    for( int d=0; d<4; d++ ){
        int nextx = x + dirs[d][0];     	 // 更新 x
        int nexty = y + dirs[d][1];          // 更新 y
        if( inArea(nextx, nexty, R, C) && grid[nextx][nexty] == 0 && !visited[nextx][nexty] )
            ans += DFS(nextx * C + nexty, end, cnt, R, C, grid);
    }
    visited[x][y] = 0;
    return ans;
}

int uniquePathsIII(int** grid, int gridSize, int* gridColSize){
    if( grid == NULL || gridSize == 0 || gridColSize == NULL || *gridColSize == 0 )
		return 0;

    int R = gridSize;          				 // 行數row
    int C = *gridColSize;       			 // 列數col


    int cnt = R * C;                         // 記錄實際要走過的點個數
    int start, end;                          // 記錄起點、終點座標          
    for( int i=0; i < R; i++ )
        for( int j=0; j < C; j++ ){
            if( grid[i][j] == 1 ){           // 【起始點】
                start = i * C + j;           // 二維索引轉一維存儲
                grid[i][j] = 0;              // 起點也可以走
            }else if( grid[i][j] == 2 ){     // 【終止點】
                end =  i * C + j;
                grid[i][j] = 0; 
            }else if( grid[i][j] == -1 ){    // 【障礙物】
                cnt --;                      // 是障礙物,所以不是實際要走的點
            }
        }
    int ans = DFS(start, end, cnt, R, C, grid);
    
    return ans;
}

優化遞歸接口,減掉不必要的參數。

int dirs[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
bool visited[20][20] = {false};

struct _graph{
    int ** _grid;
    int R;
    int C;
    int start;
    int end;
    int cnt;
} g;

bool inArea(int x, int y){     			// 判斷頂點(x, y)座標是否越界
	return x >= 0 && x < g.R && y >= 0 && y < g.C;
}

int DFS(int start, int cnt){
    /* 一維轉二維 */
    int x = start / g.C;
    int y = start % g.C;
    visited[x][y] = true;               // 起點已訪問
    cnt --;                             // 可訪問的點 -1

    if( cnt == 0 && start == g.end ){
        visited[x][y] = false;          // 回溯清除標記,爲尋找下一條路作準備
        return 1;
    }
    
    int ans = 0;
    for( int d=0; d<4; d++ ){
        int nextx = x + dirs[d][0];     // 更新 x
        int nexty = y + dirs[d][1];     // 更新 y
        if( inArea(nextx, nexty) && g._grid[nextx][nexty] == 0 && !visited[nextx][nexty] )
            ans += DFS(nextx * g.C + nexty, cnt);
    }
    visited[x][y] = false;
    return ans;
}

int uniquePathsIII(int** grid, int gridSize, int* gridColSize){
    if( grid == NULL || gridSize == 0 || gridColSize == NULL || *gridColSize == 0 )
		return 0;

    g.R = gridSize;           					// 行數row
    g.C = *gridColSize;       					// 列數col
    g._grid = grid;
    g.cnt = g.R * g.C;       		   		    // 記錄實際要走過的點個數
         
    for( int i=0; i < g.R; i++ )
        for( int j=0; j < g.C; j++ ){
            if( g._grid[i][j] == 1 ){           // 【起始點】
                g.start = i * g.C + j;          // 二維索引轉一維存儲
                g._grid[i][j] = 0;              // 起點也可以走
            }else if( g._grid[i][j] == 2 ){     // 【終止點】
                g.end =  i * g.C + j;
                g._grid[i][j] = 0; 
            }else if( g._grid[i][j] == -1 ){    // 【障礙物】
                g.cnt --;                       // 是障礙物,所以不是實際要走的點
            }
        }
    int ans = DFS(g.start, g.cnt);
    
    return ans;
}

DFS回溯哈密爾頓路徑的複雜度:

  • 時間複雜度:Θ(4n2)\Theta(4^{n^{2}})
  • 空間複雜度:Θ(n2)\Theta(n^{2})
     

算法設計:DFS狀態壓縮哈密爾頓路徑

 


算法設計:DFS記憶化搜索哈密爾頓路徑

 


算法設計:動態規劃

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章