数塔问题

来源:互联网 发布:linux 查看文件行数 编辑:程序博客网 时间:2024/05/16 10:28

数塔

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 24591    Accepted Submission(s): 14793


Problem Description
在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的:

有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?

已经告诉你了,这是个DP的题目,你能AC吗?
 

Input
输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数,且所有的整数均在区间[0,99]内。
 

Output
对于每个测试实例,输出可能得到的最大和,每个实例的输出占一行。
 

Sample Input
1573 88 1 0 2 7 4 44 5 2 6 5
 

Sample Output
30
 
 
分析:这道题其实我们可以这样转化一下:d[i][j]为从塔的底端到a[i][j]的最长路径,这样,题目的解就转化成求d[1][1]了。首先,我们知道塔的最底层肯定是它本身了,所以d[i][j] = a[i][j](i == n时),那从倒数第二行起,每个数a[i][j]可以跟最后一行合并(现在原来的倒二成倒一行),再把原来的倒3行跟原来的倒2行合并(就跟消灭星星一样,只不过我们每次都消灭最后一行,把它与前一行合并),即状态的转移!根据题意,我们推出了这个状态转移式子:a[i][j] = max(a[i][j]+a[i+1][j],a[i][j]+a[i+1][j+1])(i!=n时)把以上两步综合起来就行了。
 
 
#include <iostream>using namespace std;#define max(x,y) (x)>(y)?(x):(y);int a[150][150];//刚开始起存储矩阵原始值的作用,处理后状态转化了,储存从塔低端到a[i][j]的最长路径,也可以再用一个数组分别储存的int main(){    int  c,n;    cin >> c;    if (!c)    {        return 0;    }    while (c--)    {        cin >> n;
//填充矩阵        for (int i = 1; i <= n; i++)        {            for (int j = 1; j <= n; j++)            {                if (i < j)                {                    a[i][j] = 0;                }                else                {                    cin >> a[i][j];                }            }        }
//对矩阵做处理        for (int i = n; i >= 1; i--)        {            for (int j = n; j >= 1; j--)            {                if (i == n)                {                    a[i][j] = a[i][j];                }                else                {                    a[i][j] += max(a[i+1][j],a[i+1][j+1]);                }            }        }        cout << a[1][1] << endl;    }        return 0;}
 
//我的心得:
这是刚开始自己做的一道dp题,之前都是在看各种博客啊,前面转的那篇 《Thinking In Algorithm》13.详解动态规划问题 是我觉得挺好的博客,看了几个例题,感觉都是用递归来表达最优解的。刚开始看这题,一直在想怎么递归出最优解。起初我是从塔顶开始的,我一行一行地递归,发现第i+1行跟第i行没有所谓的后面的状态由前面决定,下一行走的路线也可能跟前一行的路线不一样呀。后来才发现这个问题分的子问题那么细。。。。
我自己瞎说的,仅供参考:
dp问题(就我看到的例题):
1.用递归的方法来推导出式子,得到最优子结构的解(最后再构造原问题解)
2.跟分治一样,把问题分成很小的子问题,此时我们可以把每个问题看成一个状态,再由每个子问题之间的关系来进行状态转移。
下面是专业人士总结的dp解题步骤:
 
1. 利用Divide and Conquer把原問題遞迴地分成許多更小的問題。(recurrence)甲、子問題與原問題的求解方式皆類似。(optimal sub-structure)乙、子問題會一而再、再而三的出現。(overlapping sub-problems)2. 確認每個問題需要哪些子問題來計算答案,並確認總共有哪些子問題。(state space)3. 決定各個問題的計算先後次序。(computational sequence)4. 安排好各個問題的答案,要存放在表格的哪個位置。(lookup table)5. 實做程式,主要有兩種方式:甲、Top-down, Recursive.乙、Bottom-up, Iterative.
 
0 0
原创粉丝点击