1. 程式人生 > 實用技巧 >4.方格取數 題解

4.方格取數 題解

Description

給定一個n\cdot mnm矩陣,找一條從(1,1)(1,1)到(n,m)(n,m)權值和最大的路徑,每次只准向上、下、右三個方向走。

\text{Solution\ 1}Solution1:暴力\text{dfs}dfs

概述:這種演算法比較簡單,不需要動頭腦,直接三方向深搜即可。

時間複雜度:\mathcal{O}(3^{nm})O(3nm)

期望得分:2020分

\text{Solution\ 2}Solution2:最優性剪枝

概述:考場上我只想到了這種方法(太菜了。我們設F_{i,j,0}Fi,j,0表示從一個格子上方走到該格子的路徑最大和,F_{i,j,1}Fi,j,1表示從一個格子右方走到該格子的路徑最大和,F_{i,j,2}Fi,j,2表示從一個格子下方走到該格子的路徑最大和。如果搜到相同的狀態則判斷是否比原FF值更大,如果更優則更新答案,否則退出該狀態。

時間複雜度:視具體資料而定,當格子權值差值較大時能拿到較多分數。

期望得分:4040分

考場\text{code}code

#include <stdio.h>
const int dx[] = {1, 0, -1}, dy[] = {0, 1, 0};
typedef long long LL;
int n, m; bool vis[1005][1005];
LL w[1005][1005], f[1005][1005][3], ans = -20000000000;
inline LL mx(LL p, LL q) {return p > q ? p : q;}
inline void dfs(int x, int y, int
from, LL now) { if (x == n && y == m) { ans = mx(now, ans); return; } if (f[x][y][from] > now) return; else f[x][y][from] = now; for (int i = 0, xx, yy; i < 3; ++i) { xx = x + dx[i]; yy = y + dy[i]; if (xx >= 1 && xx <= n && yy >= 1
&& yy <= m && !vis[xx][yy]) { vis[xx][yy] = true; dfs(xx, yy, i, now + w[xx][yy]); vis[xx][yy] = false; } } } int main(void) { // freopen("number.in", "r", stdin); freopen("number.out", "w", stdout); scanf("%d %d", &n, &m); for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) { scanf("%lld", &w[i][j]); f[i][j][0] = f[i][j][1] = f[i][j][2] = -20000000000; } vis[1][1] = true; dfs(1, 1, 0, w[1][1]); printf("%lld\n", ans); return 0; }

Solution3:記憶化搜尋

概述:這才是正解。我們設F_{i,j,0}Fi,j,0表示從一個格子上方走到該格子的路徑最大和,F_{i,j,1}Fi,j,1表示從一個格子下方走到該格子的路徑最大和。如果搜到以前搜過的狀態則直接返回搜過的最大和(也就是FF中的值),否則繼續搜尋到達該格時的最大和。

時間複雜度:\mathcal{O}(nm)O(nm)

期望得分:100100分

\text{ac\ code}accode

#include <stdio.h>
typedef long long LL;
const LL min_ll = -1e18;
int n, m; LL w[1005][1005], f[1005][1005][2];
inline LL mx(LL p, LL q, LL r) {return p > q ? (p > r ? p : r) : (q > r ? q : r);}
inline LL dfs(int x, int y, int from) {
    if (x < 1 || x > n || y < 1 || y > m) return min_ll;
    if (f[x][y][from] != min_ll) return f[x][y][from];
    if (from == 0) f[x][y][from] = mx(dfs(x + 1, y, 0), dfs(x, y - 1, 0), dfs(x, y - 1, 1)) + w[x][y];
    else f[x][y][from] = mx(dfs(x - 1, y, 1), dfs(x, y - 1, 0), dfs(x, y - 1, 1)) + w[x][y];
    return f[x][y][from];
}
int main(void) {
//    freopen("number.in", "r", stdin); freopen("number.out", "w", stdout);
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j) {
            scanf("%lld", &w[i][j]);
            f[i][j][0] = f[i][j][1] = min_ll;
        }
    f[1][1][0] = f[1][1][1] = w[1][1];
    printf("%lld\n", dfs(n, m, 1));
    return 0;
}