跳躍版圖 java 大整數 記憶化搜索 dp

題目描述

有一個 n×n 的格子,每個格子中有一個非負整數。你的目標是從左上角跳到右下角,每步只能向右或向下跳。格子中的數代表從該格開始跳躍的前進步數,如果某次跳躍會躍出格子 界限則該跳躍是禁止的。注意 0 是一個絕對終點,因爲從這裏無法再移動。


你的任務是統計有多少種合法路徑。上圖 1 中共有 3 種路徑,分別表示在圖 2 中。

輸入
第一行,一個整數 n(3 ≤ n ≤ 100)。

接下來 n 行 n 列,表示格子中的數,所有數的範圍在[0,9]中,兩個數之間用一個空格隔開。

輸出

第一行,從左上角到右下角的合法路徑數目。

樣例輸入
4
2 3 3 1
1 2 1 3
1 2 3 1
3 1 1 0

樣例輸出
3

思路

裸記憶化搜索,從(1,1)開始朝兩個方向深度優先搜索,搜索完一個節點之後,然後用一個DP數組存儲即可,但是得注意對終點(mp[i][j] == 0)的特判退出情況,否則會爆棧。

代碼

import java.util.Scanner;
import java.math.BigInteger;
 
public class Main {
    static BigInteger dp[][]=new BigInteger[110][110];
    static int[][] mp=new int[110][110];
    static int dir[][]=new int[2][2];
    static int n;
     
    static BigInteger dfs(int x,int y){
        if(dp[x][y].compareTo(BigInteger.ZERO)>0) return dp[x][y];
        for(int i=0;i<2;i++){
            int xx=dir[i][0]*mp[x][y]+x;
            int yy=dir[i][1]*mp[x][y]+y;
            if(x==xx&&y==yy) return BigInteger.ZERO;
            else if(xx==n&&yy==n){
                dp[x][y]=dp[x][y].add(BigInteger.ONE);
                continue;
            }
            if(xx>=1&&xx<=n&&yy>=1&&yy<=n)
                dp[x][y]=dp[x][y].add(dfs(xx,yy));
        }
        return dp[x][y];
    }
     
    public static void main(String[] args) {
        Scanner scan =new Scanner (System.in);
        while(scan.hasNext()) {
            n=scan.nextInt();
            for(int i=1;i<=n;i++) {
                for (int j=1; j<=n;j++) {
                    mp[i][j]=scan.nextInt();
                }
            }
            dir[0][1]=dir[1][0]=1;
            dir[0][0]=dir[1][1]=0;
            for(int i=1;i<=n;i++) {
                for(int j=1;j<=n;j++) {
                    dp[i][j]=BigInteger.ZERO;
                }
            }
            dfs(1,1);
            System.out.println(dp[1][1]);
        }
         
    }
}
學如逆水行舟,不進則退
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章