Optimization 如何最大化路径的价值?
我们得到一个N*N网格。我们最初在网格的左上角。网格的每一个方格都有一些附加值,也就是说,如果有人到达该方格,他将赢得与该方格附加值相等的美元金额。现在的法律行动是向右转一步,或者向底部走一步。我们必须到达网格的右下角,这样我们才能最大化赢得的资金。显然,我们必须呆在网格内,不能偏离网格。 我用一种贪婪的方法开始这个问题,在每一步中,我们都会看到右边的正方形和占据的正方形下面的正方形,然后在每一步中选择具有更高值的正方形。但这并不总是给出正确的结果。例如,在下面的网格中Optimization 如何最大化路径的价值?,optimization,dynamic-programming,Optimization,Dynamic Programming,我们得到一个N*N网格。我们最初在网格的左上角。网格的每一个方格都有一些附加值,也就是说,如果有人到达该方格,他将赢得与该方格附加值相等的美元金额。现在的法律行动是向右转一步,或者向底部走一步。我们必须到达网格的右下角,这样我们才能最大化赢得的资金。显然,我们必须呆在网格内,不能偏离网格。 我用一种贪婪的方法开始这个问题,在每一步中,我们都会看到右边的正方形和占据的正方形下面的正方形,然后在每一步中选择具有更高值的正方形。但这并不总是给出正确的结果。例如,在下面的网格中 { 6, 9,
{ 6, 9, 18, 1 }
{ 2, 10, 0, 2 }
{ 1, 100, 1, 1 }
{ 1, 1, 1, 1 }
这里我的算法给出的最大值路径为
6 -> 9 -> 18 -> 1 -> 2 -> 1 -> 1
总数为37,但我们本可以在这条路上赚更多
6 -> 9 -> 10 -> 100 -> 1 -> 1 -> 1
总共有128个。你们能帮我建立一个合适的算法吗?我还没有编写这个代码,因为它无论如何都会给出错误的输出。我不知道如何在没有暴力的情况下处理这个问题,暴力包括看到所有路径中不包含最小值的平方的值,然后找到最大值
#include <iostream>
#include <queue>
using namespace std;
int main()
{ int n; cin >> n;
int a[n+1][n+1], b[n+1][n+1];
for (int i=0;i<n;i++)
{
for (int j=0;j<n;j++)
{
cin >> a[i][j]; b[i][j]=a[i][j];
}
}
queue <int> q; int u,v,m=0;
q.push(0);q.push(0);
while (q.size()!=0)
{
u=q.front(); q.pop(); v=q.front(); q.pop();
if (v<n-1)
{
m=b[u][v]+a[u][v+1];
if (m>b[u][v+1])
{ b[u][v+1]=m; }
q.push(u);q.push(v+1);
}
if (u<n-1)
{
m=b[u][v]+a[u+1][v];
if (m>b[u+1][v])
{ b[u+1][v]=m; }
q.push(u+1);q.push(v);
}
}
cout << b[n-1][n-1];
return 0;
}
#包括
#包括
使用名称空间std;
int main()
{int n;cin>>n;
int a[n+1][n+1],b[n+1][n+1];
对于(int i=0;i a[i][j];b[i][j]=a[i][j];
}
}
队列q;int u,v,m=0;
q、 推(0);q.push(0);
而(q.size()!=0)
{
u=q.front();q.pop();v=q.front();q.pop();
if(vb[u][v+1])
{b[u][v+1]=m;}
q、 推力(u);q推力(v+1);
}
如果(ub[u+1][v])
{b[u+1][v]=m;}
q、 推力(u+1);q推力(v);
}
}
cout实际上,这是一个使用动态规划可以解决的问题。您只需要调整算法来计算编辑距离,以允许不同的奖励。
例如,在中描述了该算法
其基本思想是,从顶部开始,填充一个正方形,无论何时填充它的相邻(顶部,左侧)字段。
您在字段中输入的值是两个相邻字段中较高者的值和当前字段的值。当您到达右下角时,您只需沿着路径返回即可。问题可以通过以下方法解决。位于(i,j)
位置的每个单元格都与值val(i,j)关联
这是通过从位置(0,0)
开始的所述合法移动(底部、右侧)达到的最大可能总值。位置(0,0)
处的值是来自网格的值,在后继中称为网格(i,j)
对于{0,…,N-1}中的每个i,j
。我们得到以下递归关系
val(i,j) = grid(i,j) + max{ val(i-1,j), // path coming from upper cell
val(i,j-1) // path coming from left cell
}
其中,我们假设{0,…,N-1}*{0,…,N-1}
之外的索引产生负无穷大的值,并且从未真正使用过。递归关系是有效的,因为到达一个单元格最多有两种情况,即从其上邻居或其左邻居(除了边界上的牢房,可能只有一个邻居可以到达)
有效计算val
的关键是按顺序组织值的计算,以便所有需要的邻域都已计算;这可以通过依次开始计算尚未计算val
的最左侧单元格并从该单元格向上向右移动来完成r,直到到达最上面一行。这将迭代,直到计算位置val(N-1,N-1)
,从而得到所需的结果
如果另外需要(N-1,N-1)
的特定路径,则必须使用回溯或某些辅助数据结构来存储如何计算上述递推关系中的值,即哪个项产生最大值
#include <iostream>
#include <queue>
using namespace std;
int main()
{ int n; cin >> n;
int a[n+1][n+1], b[n+1][n+1];
for (int i=0;i<n;i++)
{
for (int j=0;j<n;j++)
{
cin >> a[i][j]; b[i][j]=a[i][j];
}
}
queue <int> q; int u,v,m=0;
q.push(0);q.push(0);
while (q.size()!=0)
{
u=q.front(); q.pop(); v=q.front(); q.pop();
if (v<n-1)
{
m=b[u][v]+a[u][v+1];
if (m>b[u][v+1])
{ b[u][v+1]=m; }
q.push(u);q.push(v+1);
}
if (u<n-1)
{
m=b[u][v]+a[u+1][v];
if (m>b[u+1][v])
{ b[u+1][v]=m; }
q.push(u+1);q.push(v);
}
}
cout << b[n-1][n-1];
return 0;
}
编辑
或者,计算可以从左到右逐行进行,这也具有所需的属性,即已经计算了递归关系的所有必要值;这显然更容易实现。在任何一种情况下,运行时界限都将是O(n^2)
这是一个可以解决的经典问题。请向我们展示您迄今为止在代码方面取得的成就。@miensol注意,原始海报中没有使用“动态规划”一词,我怀疑他或她对此概念不熟悉,因此暗示可以通过动态规划解决(其本身正确且完全有效)不是从问题的角度来解决问题。@Codor你是对的,当然,我不想透露完整的解决方案,因为这很可能是一项家庭作业。因此,我想看看海报上实际上有一些代码要显示。@miensol很好。原始海报能否澄清这是否真的是家庭作业?@Codor,w恕我直言,我看到了完全相同的dp解决方案,这对我来说是一个非常熟悉的概念,但对我来说似乎有点复杂,所以我在寻找另一种方法。我忘了提到这不是一个家庭作业问题,因为许多用户在这里发布了家庭作业问题。这是在2010年的一次奥运会上发布的,我正在阅读论文s、 官方的解决方案使用了dp,但正如我所说,它看起来很复杂,所以我用了另一种方法。这是我的代码链接,我花了一些时间学习dijkstra,我使用了相同的修改形式。现在我看到了dp,它看起来很简单,但我以前从未实现过2d dp。不过我知道一些问题,如硬币计数ng和背包由2d dp解决,你能给出这个问题的代码吗?这将帮助我学习实现2d dp。@user260674谢谢你的反馈,但是堆栈溢出不是一个代码编写服务。你可以使用访问函数读取返回“负无穷大”(或最小v)的数组值