使用两次遍历收集网格中的最大点
dynamic programmingalgorithmsdata structure
每个单元格中都有一个点的矩阵,如何使用两次遍历从该网格中获得最大点。
有一些条件需要满足−
- 第一次遍历从网格的左上角单元格开始,应该到达左下角。 第二次遍历从右上角开始到右下角
- 从一个单元格我们只能移动到当前单元格的底部、左下角和右下角。
- 如果一次遍历已经从某个单元格获得一些点,则在下一次遍历中不会从该单元格获得任何点。
输入和输出
输入: A grid with points. 3 6 8 2 5 2 4 3 1 1 20 10 1 1 20 10 1 1 20 10 输出: Maximum points collected by two traversals is 73. From the first traversal, it gains: 3 + 2 + 20 + 1 + 1 = 27 From the second traversal, it gains: 2 + 4 + 10 + 20 + 10 = 46
算法
findMaxVal(mTable, x, y1, y2)
输入 − 一个三维数组作为记忆表,x值和y1,y2。
输出 − 最大值。
Begin if x, y1 and y2 is not valid, then return - ∞ if both traversal is complete, then if y1 = y2, then return grid[x, y1] else return grid[x, y1] + grid[x, y2] if both traversal are at last row, then return - ∞ if subProblem is solved, then return mTable[x, y1, y2] set res := - ∞ if y1 = y2, then temp := grid[x, y1] else temp := grid[x, y1] + grid[x, y2] res := max of res and (temp + findMaxVal(mTable, x+1, y1, y2-1)) res := max of res and (temp + findMaxVal(mTable, x+1, y1, y2+1)) res := max of res and (temp + findMaxVal(mTable, x+1, y1, y2)) res := max of res and (temp + findMaxVal(mTable, x+1, y1-1, y2)) res := max of res and (temp + findMaxVal(mTable, x+1, y1-1, y2-1)) res := max of res and (temp + findMaxVal(mTable, x+1, y1-1, y2+1)) res := max of res and (temp + findMaxVal(mTable, x+1, y1+1, y2)) res := max of res and (temp + findMaxVal(mTable, x+1, y1+1, y2-1)) res := max of res and (temp + findMaxVal(mTable, x+1, y1+1, y2+1)) return true if mTable[x, y1, y2] = res End
示例
#include<iostream> #define ROW 5 #define COL 4 using namespace std; int grid[ROW][COL] = { {3, 6, 8, 2}, {5, 2, 4, 3}, {1, 1, 20, 10}, {1, 1, 20, 10}, {1, 1, 20, 10}, }; bool isValidInput(int x, int y1, int y2) { return (x >= 0 && x < ROW && y1 >=0 && y1 < COL && y2 >=0 && y2 < COL); } int max(int a, int b) { return (a>b)?a:b; } int findMaxVal(int mTable[ROW][COL][COL], int x, int y1, int y2) { if (!isValidInput(x, y1, y2)) //当在无效单元格中时,返回负无穷 return INT_MIN; if (x == ROW-1 && y1 == 0 && y2 == COL-1) //当两个遍历都完成时 return (y1 == y2)? grid[x][y1]: grid[x][y1] + grid[x][y2]; if (x == ROW-1) //两次遍历都在最后一行但尚未完成 return INT_MIN; if (mTable[x][y1][y2] != -1) //当子问题解决时 return mTable[x][y1][y2]; int answer = INT_MIN; //最初答案是负无穷 int temp = (y1 == y2)? grid[x][y1]: grid[x][y1] + grid[x][y2]; //存储当前房间的增益 //找到所有可能值的答案并取其中的最大值 answer = max(answer, temp + findMaxVal(mTable, x+1, y1, y2-1)); answer = max(answer, temp + findMaxVal(mTable, x+1, y1, y2+1)); answer = max(answer, temp + findMaxVal(mTable, x+1, y1, y2)); answer = max(answer, temp + findMaxVal(mTable, x+1, y1-1, y2)); answer = max(answer, temp + findMaxVal(mTable, x+1, y1-1, y2-1)); answer = max(answer, temp + findMaxVal(mTable, x+1, y1-1, y2+1)); answer = max(answer, temp + findMaxVal(mTable, x+1, y1+1, y2)); answer = max(answer, temp + findMaxVal(mTable, x+1, y1+1, y2-1)); answer = max(answer, temp + findMaxVal(mTable, x+1, y1+1, y2+1)); return (mTable[x][y1][y2] = answer); //将答案存储在 mTable 中并返回。 } int findMaxCollection() { // 创建一个记忆表并将所有值设置为 -1 int mTable[ROW][COL][COL]; for(int i = 0; i<ROW; i++) for(int j = 0; j<COL; j++) for(int k = 0; k<COL; k++) mTable[i][j][k] = -1; return findMaxVal(mTable, 0, 0, COL-1); } int main() { cout << "最大集合为" << findMaxCollection(); return 0; }
输出
最大集合为 73