我很难想出一种为动态编程问题制定解决方案的方法。基本上,我必须从NxN数组中的左上角到右下角元素,只能向下或向右移动,但我应该移动到更大的元素并将其与变量相加(通过仅向右移动获得最高分数和下来)。 F.e.,如果我有这个矩阵:
0 1 1
0 4 2
1 1 1
它应该移动0-> 1 - > 4 - > 2 - > 1并打印8。 我已经阅读了很长一段时间的动态优化,但仍然无法解决这个问题。如果有人能帮助我,我将不胜感激。 提前谢谢!
编辑:谢谢@sestus!我设法解决了这个问题,但解决方案很慢,我必须对其进行优化才能更快地完成。这是我的解决方案:
#include <iostream>
#include <algorithm>
using namespace std;
const int MAX = 100;
int arr[MAX][MAX];
int move(int row,int col, int n)
{
if(row >= n || col >= n)
{
return 0;
}
return max(arr[row][col] + move(row + 1, col, n),
arr[row][col] + move(row, col + 1, n));
}
int main()
{
int examples, result;
cin>>examples;
int n;
int results[examples];
for(int k =1; k <= examples; k++)
{
cin >> n;
int s = 0;
int i = 0, j = 0;
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++)
{
cin>> arr[i][j];
}
}
i = 0, j = 0;
s+=move(i,j, n);
results[k] = s;
}
for(int k = 1; k <= examples; k++)
{
cout<<results[k]<<endl;
}
return 0;
}
(程序实际上必须采取所有示例并在最后输出所有这些示例的答案)。介意帮助我优化?
答案 0 :(得分:2)
我不会在这里粘贴准备好的代码,我只是给你一个解决方案的高级描述。
那么在决定搬家的时候你有什么可能的选择?您可以向下或向右移动,添加当前块的值。您的目标是最大化您访问过的块的总和,直到您到达右下方块为止。这给了我们:
move(row, column):
//handle the cases when you move out of bounds of the array here
return(max{array[row,column] + move(row + 1, column),
array[row,column] + move(row, column + 1)})
要使上述成为一个完整的动态编程解决方案,您需要添加一些记忆,例如获取已经解决的问题的值,而无需再次计算它们。请在stackoverflow上查看此内容以获取更多详细信息:Dynamic programming and memoization: bottom-up vs top-down approaches
例如,拿这个董事会:
注意两条不同的路线。我们通过两条不同的路线到达block[1][2]
(红线和蓝线的值为3的那条)。根据蓝色路线,我们向右右移动,而我们通过读取右移向右移动。我粘贴的伪代码规定我们将首先采用蓝色路由,因为我们在递归调用move(row + 1, column)
之前遇到递归调用move(row, column + 1)
。
因此,当我们从红色路线到达block[1][2]
时,我们实际上并不需要再次计算此解决方案。我们已经完成了这个,当我们通过阅读路线到达那里时!如果我们将这个解决方案保存在一个数组(或一个map / hash表)中,我们就可以选择解决方案,而无需再次计算它。那是记忆!
基于以上所述,您可以使用地图,因为您正在使用c ++:
std::map<std::pair<int, int>, int> cache;
在进行递归调用之前,您需要检查该对是否存在于地图中。如果没有,则将其添加到地图中。所以移动变成:
int move(int row,int col, int n)
{
if(row >= n || col >= n)
{
return 0;
}
pair<int, int> rowplus_column = make_pair(row + 1,col);
pair<int, int> row_columnplus = make_pair(row, col + 1);
int solution_right = 0;
int solution_down = 0;
map<char, int>::iterator it;
it = cache.find(rowplus_column);
if (it == cache.end()) {
solution_down = move(row + 1, col);
cache.insert(rowplus_column, solution_down);
}
else {
solution_down = it->second;
}
it = cache.find(row_columnplus);
if (it == cache.end()) {
solution_right = move(row, col + 1);
cache.insert(row_columnplus, solution_right);
}
else {
solution_right = it->second;
}
return max(arr[row][col] + solution_down,
arr[row][col] + solution_right);
}
我在C ++中有点生疏,但希望你有这个想法: 在实际计算解决方案之前,请检查该对的映射。如果该对存在,那么您已经解决了问题的这一部分,所以从地图中获取解决方案并避免递归调用。