题目
有一个 X×Y 的网格,一个机器人只能走格点且只能向右或向下走,要从左上角走到右下角。请设计一个算法,计算机器人有多少种走法。给定两个正整数x,y,请返回机器人的走法数目。
- 测试输入:
2 2 - 测试输出:
2
分析1
使用动态规划求解,定义 n[i,j] 为从起点 [0,0] 到点 [i,j] 的走法数目,则递归式为
n[i,j]={1,n[i−1,j]+n[i,j−1],i=0 or j=0i,j≠0
代码1
import java.util.Scanner;
public class Robot {
static void solution(int[][] n, int x, int y) {
for (int j = 0; j < y; j++) {
n[0][j] = 1;
}
for (int i = 0; i < x; i++) {
n[i][0] = 1;
}
for (int i = 1; i < x; i++) {
for (int j = 1; j < y; j++) {
n[i][j] = n[i - 1][j] + n[i][j - 1];
}
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int x = sc.nextInt();
int y = sc.nextInt();
int[][] n = new int[x][y];
solution(n, x, y);
System.out.println(n[x - 1][y - 1]);
}
}
变形
实际上机器人走过的水平和垂直网格数目是固定的 x+y−2 ,可以先安排水平的走法有 x−1 个,那么剩下的就安排给垂直走法,所以总的走法数目可以用组合计算为 Cx−1x+y−2 。但为什么还用动态规划计算呢?这个题目有灵活的变形。如果规定网格中的某些点机器人不能经过,那么动态规划就是一种通用的解法了。
给定两个正整数
x
,
- 测试输入:
3 3
1
1 1 - 测试输出:
2
分析2
只需要将禁止点设置为不可行点,每次计算将其排除即可。递归式为
代码2
import java.util.Scanner;
public class Robot {
static boolean isForbidden(int x, int y, int[] xforbid, int[] yforbid) {
int length = xforbid.length;
for (int i = 0; i < length; i++) {
if (x == xforbid[i] && y == yforbid[i]) return true;
}
return false;
}
static void solution(int[][] n, int x, int y, int[] xforbid, int[] yforbid) {
for (int j = 0; j < y; j++) {
n[0][j] = 1;
}
for (int i = 0; i < x; i++) {
n[i][0] = 1;
}
for (int i = 1; i < x; i++) {
for (int j = 1; j < y; j++) {
if (isForbidden(i, j, xforbid, yforbid))
n[i][j] = Integer.MIN_VALUE;
else if (n[i - 1][j] == Integer.MIN_VALUE &&
n[i][j - 1] == Integer.MIN_VALUE) {
n[i][j] = Integer.MIN_VALUE;
} else if (n[i - 1][j] != Integer.MIN_VALUE &&
n[i][j - 1] == Integer.MIN_VALUE) {
n[i][j] = n[i - 1][j];
} else if (n[i - 1][j] == Integer.MIN_VALUE &&
n[i][j - 1] != Integer.MIN_VALUE) {
n[i][j] = n[i][j - 1];
} else {
n[i][j] = n[i - 1][j] + n[i][j - 1];
}
}
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int x = sc.nextInt();
int y = sc.nextInt();
int[][] n = new int[x][y];
int nforbid = sc.nextInt();
int[] xforbid = new int[nforbid];
int[] yforbid = new int[nforbid];
for (int i = 0; i < nforbid; i++) {
xforbid[i] = sc.nextInt();
yforbid[i] = sc.nextInt();
}
solution(n, x, y, xforbid, yforbid);
System.out.println(n[x - 1][y - 1]);
}
}