使用动态规划,从最后一个状态进行分解,设 dp[i][j] 表示在坐标(i,j)处能得到的最小总和,因为下一个点只能是当前点下方一个点,或者右下方一个点,那么 dp[i][j] 的表达式就是   dp[i][j] = min( dp[i-1][j],dp[i-1][j-1] ) +  c[i][j], c[i][j]表示当前点的数值。
需要注意两个特殊情况,就是当 j = 0 时,dp[i][j] 只能是当前点的数值加上 dp[i-1][j],因为没有其他位置可以走到这里。还有就是 i = j 的时候,dp[i][j] 只能是当前点数值加上 dp[i-1][j-1]。需要在循环填充dp表的时候设置判断条件。
根据状态转移方程可以看出 dp[i][j] 的状态之和 dp[i-1][j] 和 dp[i-1][j-1] 相关而且只在 i >= j时候有意义,所以在填充dp表的时必须是每一列依次往下填充。


int min(const int a,const int b)
{
    return a<b?a:b;
}


int minTrace(int** triangle, int triangleRowLen, int* triangleColLen ) 
{
    // write code here
    int dp[triangleRowLen][triangleRowLen];
    memset(dp, 0, sizeof(dp));
    
    for( int j = 0; j < triangleRowLen; ++j )
    {
        for( int i = j; i < triangleRowLen; ++i )
        {
            if( !j )                                           //j = 0 的情况
            {
                if( !i ) dp[i][j] = triangle[0][0];            //其实dp[0][0]是dp表的初始状态,但是写程序的时候发现在一开始设置好初始状态,for循环不好写,所以直接写进来                            
                else
                    dp[i][j] = dp[i-1][j] + triangle[i][j];
            }
            else if( j != 0 && i == j ) dp[i][j] = dp[i-1][j-1] + triangle[i][j];  //对角线的情况
            else dp[i][j] = min( dp[i-1][j-1],dp[i-1][j] ) + triangle[i][j];       //其余情况
        }
    }
    int res = dp[triangleRowLen-1][0];
    for( int i = 0; i < triangleRowLen; ++i )                                      //比较最后一行的所有数据,选出最小的就是答案
    {
        if( dp[triangleRowLen-1][i] < res ) res = dp[triangleRowLen-1][i];
    }
    
    return res;
}


最近一直在刷动态规划的题目,从刚开始的猪脑过载到自己能写出来,把结题思路记录下来,方便以后回看。之后会把之前刷过的题再整理一遍记录下来,希望秋招的时候考到的全是刷过的。
刷了这么多天的题,对于动态规划的解题思路主要是 从最后一个状态开始分解问题,写出转移方程,根据建立的dp表(一维,二维。。。)所代表的含义确定起始状态。再填充dp表。可能会忽视的点就是要根据转移方程确定填充方式,因为动态规划的当前状态之和前状态相关。