拜访(动态规划)

来源:互联网 发布:c语言枚举法例题 编辑:程序博客网 时间:2024/04/28 10:15

题目描述

现在有一个城市销售经理,需要从公司出发,去拜访市内的商家,已知他的位置以及商家的位置,但是由于城市道路交通的原因,他只能在左右中选择一个方向,在上下中选择一个方向,现在问他有多少种方案到达商家地址。给定一个地图map及它的长宽n和m,其中1代表经理位置,2代表商家位置,-1代表不能经过的地区,0代表可以经过的地区,请返回方案数,保证一定存在合法路径。保证矩阵的长宽都小于等于10。

测试样例:
[[0,1,0],[2,0,0]],2,3
返回:2

解题思路:
因为题目限制了在某个位置经理只能往两个方向走,所以就经理全程只有四种可以走的走法分别为左上、左下、右上、右下。所以一开始要判断经理和商家的方向,找到其行走的方向,若商家在经理的左下方则经理全程只能向左或者向下行走。
例如经理在黄色位置,商家在蓝色位置,橘色的为不能走的位置,空白的为可以走的路径,则经理只能往左下走。
这里写图片描述
动态规划思想:
每一个位置可以走的位置可以由其左上、左下、右上、右下相加得到,当选定一个方向之后只能由该方向的相加得到,如上面的例子只能由其上方和右边两个位置可达路径相加。
所以一开始只能由经理所在的位置往商家所在的位置斜着移动,动态的获得路径和。
经理只能往下或者往走,所以其到商家的位置等于商家所在的位置的上方位置的可达路径数+商家所在的位置的右方的可到达路径数的和,即为2。
这里写图片描述

代码
public int countPath(int[][] map, int n, int m) {
// write code here
// int solveSum = 0;
int r = 0, c = 0;
int comRow = -1, comCol = -1, businessRow = -1, businessCol = -1;
// 寻找公司和商人所在的位置
for (r = 0; r < n; r++) {
for (c = 0; c < m; c++) {
if (map[r][c] == 1) {
comRow = r + 1;// 公司所在的行,+1是方便后面进行计算
comCol = c + 1;// 公司所在的列,+1是方便后面进行计算
}
if (map[r][c] == 2) {
businessRow = r + 1;// 商人所在的行,+1是方便后面进行计算
businessCol = c + 1;// 商人所在的列,+1是方便后面进行计算
}
if (comRow != -1 && businessRow != -1)
break;
}
}
int rd = businessRow - comRow, cd = businessCol - comCol;
int solveMap[][] = new int[n + 2][m + 2];// 解决方案矩阵
for (r = 0; r < n; r++) {
for (c = 0; c < m; c++) {
if (map[r][c] != -1)
solveMap[r + 1][c + 1] = 0;
else
solveMap[r + 1][c + 1] = -1;
}
}
for (r = 0; r < n + 2; r++) {// 外围的解都等于-1不可达
solveMap[r][0] = -1;
solveMap[r][m + 1] = -1;
}
for (c = 0; c < m + 2; c++) {
solveMap[0][c] = -1;
solveMap[n + 1][c] = -1;
}

    int tmp = 0;    tmp = comRow;    int rdirection = businessRow > comRow ? 1 : -1;    for (r = 0; r < Math.abs(rd); r++) {// 处理和该公司所在列的可达方案数顶多为1        tmp = tmp + rdirection;// 判断是加还是减        if (solveMap[tmp][comCol] == -1 || solveMap[tmp - rdirection][comCol] == -1)            solveMap[tmp][comCol] = -1;// 判断当前位置是否为-1,或者前一行是否为-1        else            solveMap[tmp][comCol] = 1;// 当前位置都为1    }    tmp = comCol;    int cdirection = businessCol > comCol ? 1 : -1;    for (c = 0; c < Math.abs(cd); c++) {        tmp = tmp + cdirection;// 判断是加还是减        if (solveMap[comRow][tmp] == -1 || solveMap[comRow][tmp - cdirection] == -1)            solveMap[comRow][tmp] = -1;        else            solveMap[comRow][tmp] = 1;// 当前位置的为1    }    // for(r=0; r < n+2; r++){    // for(c = 0; c < m+2; c++){    // System.out.print(solveMap[r][c]+" ");    // }    // System.out.println();    // }    // 动态规划求解    int tmpRow = comRow;    for (r = 0; r < Math.abs(rd); r++) {        int tmpCol = comCol;        tmpRow += rdirection;        for (c = 0; c < Math.abs(cd); c++) {            tmpCol += cdirection;            solveMap[tmpRow][tmpCol] = towSum(solveMap[tmpRow][tmpCol - cdirection],                    solveMap[tmpRow - rdirection][tmpCol]);// 等于前一行或者同行两个的和        }    }    // for(r=0; r < n+2; r++){    // for(c = 0; c < m+2; c++){    // System.out.print(solveMap[r][c]+" ");    // }    // System.out.println();    // }    return solveMap[businessRow][businessCol];}/** * 返回两个数的正数和,若两则都为负数则返回0 * @param a * @param b * @return */int towSum(int a, int b) {    int sum = a;    if (a < 0)        sum = 0;    if (b > 0)        sum = sum + b;    return sum;}

这个题目理解了半天,描述的不是很清楚,经理到商家只能向两个方向移动,其他方向不能移动。

0 0