我的动态编程方法哪里出错了?

Posted

技术标签:

【中文标题】我的动态编程方法哪里出错了?【英文标题】:Where does my dynamic programming approach goes wrong? 【发布时间】:2016-02-25 16:32:11 【问题描述】:

我正在尝试解决这个 spoj 问题http://www.spoj.com/problems/BYTESM2/

这是我迄今为止尝试过的代码,

#include <iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int a[101][101],Table[101][101]=0;
int pickStones(int i,int j,int n,int m,int sum)

    int k,l,p;
    int stones=0;
    if(i>n||j>m||j<0)
    return 0;
    else if(i==n)
    return Table[i][j]=sum;
    else
    
        if(Table[i][j]==0)
        
            if(Table[i+1][j]==0)
        Table[i+1][j]=pickStones(i+1,j,n,m,sum+a[i][j]);
        if(Table[i+1][j-1]==0)
        Table[i+1][j-1]=pickStones(i+1,j-1,n,m,sum+a[i][j]);
        if(Table[i+1][j+1]==0)
        Table[i+1][j+1]=pickStones(i+1,j+1,n,m,sum+a[i][j]);
        stones=max(Table[i+1][j],Table[i+1][j-1]);
        stones=(max(stones,Table[i+1][j+1]));
        Table[i][j]=stones;
        
        return Table[i][j];
    

int main() 
    int t,n,m,l=0,h=0,max;
    scanf("%d",&t);
    while(t--)
    
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
        scanf("%d",&a[i][j]);
        max=a[0][0];
        for(int i=0;i<m;i++)
        if(a[0][i]>max)
        
            max=a[0][i];
            l=0;h=i;
        
        printf("%d\n",pickStones(l,h,n,m,0));
    
    return 0;

如果我摆脱动态编程 Table[][] 数组并将 `pickStones() 的结果存储在变量中并将问题实现为普通递归,我会得到正确的答案,但我不知道其中的重叠子问题在哪里以及如何存储它们以避免再次计算。

【问题讨论】:

我想你误解了什么是动态规划。***关于 levenshtein distance 的条目特别清楚:DP 只是一个递归,没有“表”。不幸的是,幼稚的实现通常永远运行,因此在一个有效的实现中,先前计算的子问题的结果存储在一个表中。在这种情况下,没有递归调用,表是从先前计算的条目中填充的。您正在混合这个想法及其可能的实现之一。 DP 只是一个递归,没有“表”。不幸的是,幼稚的实现通常永远运行,因此在一个有效的实现中,先前计算的子问题的结果存储在一个表中。 正是,这就是我想要实现的,将预先计算的结果存储在 Table[][]大批。问题是我找不到重叠的子问题并存储结果,尽管我可以通过简单的递归得到答案。 能否请您发布没有“表格”的“正确”代码? 您的“表格”的每个单元格都将包含一个数字,该数字是哈利从该单元格开始到最后一行的任何路径上可以拾取的最大石头数。最初所有单元格都为零。您可以在不移动的情况下填充哪些单元格?答案:最后(h-th)行的所有单元格。现在,给定最后一行的值,您可以通过取三个可访问单元格中的最大值加上该单元格上的石头数来计算第 h-1 行的数量。子问题是你可以从第 h 行捡起的石头的数量......但这已经填好了,所以没有递归。然后你倒退到第一行。 【参考方案1】:

您想要一个解决方案,或者解释为什么您的代码不起作用? 无论如何,我会先给出我的 AC 代码。

#include<bits/stdc++.h>
using namespace std;

int w[200][200] = 0, dp[200][200] = 0;
int t,r,c;
int main()
    cin >> t;
    while(t--)
        cin >> r >> c;
        memset(w,0,sizeof(w)); memset(dp,0,sizeof(dp));
        for(int i=1; i<=r ;i++) for(int j=1; j<=c; j++)  
            cin >> w[i][j]; dp[1][j] = w[1][j];
        
        for(int i=2; i<=r; i++) for(int j=1; j<=c; j++) 
            dp[i][j] = w[i][j] + max(dp[i-1][j-1], max(dp[i-1][j], dp[i-1][j+1]));
        int ans = 0;
        for(int i=1; i<=c;i++) ans = max(ans, dp[r][i]);
        cout << ans << endl;
    

为您的代码

 max=a[0][0];
 for(int i=0;i<m;i++)
     if(a[0][i]>max)
     
         max=a[0][i];
         l=0;h=i;
     

您是否选择第一行的最大棋子列开始? 这可能并不总是正确的。

【讨论】:

保持80~120个字符的最大行长,否则其他人将不得不滚动阅读您的代码

以上是关于我的动态编程方法哪里出错了?的主要内容,如果未能解决你的问题,请参考以下文章

Python面向对象编程高级特性

我将如何解决这个曼哈顿天际线/石墙的方法,我哪里出错了? Javascript

编程艺术python importlib 动态调用 py 脚本方法

正确地将第二个动态模板添加到 Gatsby/NetlifyCMS - 我哪里出错了?

GroovyMOP 元对象协议与元编程 ( 方法合成 | 动态注入方法 )

android编程如何在View的onTouch方法里面动态的画图