artificerpi

探索数字迷塔问题及遇到指针无法访问内存的错误

Problem : 探索数字迷塔

Time Limit: 1 Sec  Memory Limit: 64 MB

Description

晶晶最近迷上了数字迷宫游戏,整天沉浸在一串串看似简单的数字中自得其乐。数字迷宫游戏的魅力体现在变化中隐含着不变的规律,归纳是探究数字迷宫的法宝之一。图10.1-1就是一个由线连接起来的数字小方格组成的数字迷塔。

这个迷塔共n层,它由n×(n+1)/2个小方格组成。每个小方格中都有一个数字,并且连着下一层的两个小方格。现从塔顶走到塔底,每一步只能走到相邻的方格中,则经过方格的数字之和最大值是多少?这个问题晶晶已经琢磨一天了,她感觉异常棘手。你能帮帮她吗?

Input

输入数据共n+1行,第1行是一个整数n(1≤n≤1000),表示数字迷塔的高度,接下来用n行数字表示数字迷塔,其中第i行有i个正整数,且所有的正整数均不大于100。

Output

输出可能得到的最大和。

Sample Input

5

9

12 15

10 6 8

2 18 9 5

19 7 10 4 16

Sample Output

59

HINT

样例说明:9→12→10→18→10

 

方法策略

  对于这个问题,首先我想到的是从特殊到一般的方法,即先考虑一个较少的输入范围,如输入高度为5,然后思考如何用实际方法解决这个问题,再得出一般性的结论。先来分析这个特殊的树,它是有向的图,每个节点(除叶子外)都有两个子节点,而且相邻两个节点还共有一个子节点。很容易把它想象一个楼梯的模型,那么父节点与子结点的位置关系就很清楚了,即子节点在父节点的正下方和右下角,所以遍历这棵树和建立树的结构就迎刃而解了。对于求最大消耗路径问题,考虑到父子节点间的关系,可以采用用动态规划的方法解决,即:

cost(总)= cost(父) +  MAX(cost(子左),cost(子右))

找到了递推关系,应该很容易计算出结果了。

  具体如何建立这棵树呢?首先,还是用老办法,定义一个结构来表示每个节点(含数据,左、右指针等成员)。然后考虑如何输入数据和初始化所有节点:首先定义一个方法,输入是树的高度,输出是根节点的地址(便于访问树);利用树的高度信息及确定每层所含节点的数目,所以可以直接用动态数组来生成每层的节点,但是同时还要保留该数组的首地址,便于下面访问节点,所以需要创建一个二级指针来记录; 最后用两层循环来让父结点的指针指向子节点即可。

 

相应代码:

 1 /*
 2  *  numberati.cpp
 3  *  Copyright 2015 Kevin <Kevin@YU_WINDOWS8>
 4  *  
 5  *  This program is intented to solve the Digit Magic Tower problem.
 6  *
 7  */
 8 
 9 #include<iostream>
10 using namespace std;
11 
12 /* Definiton of Node with the struct type*/
13 struct Node{
14     int data;
15     Node * left;
16     Node * right;      
17 };
18 
19 /* Function Declaration */
20 Node * buildTree();
21 int findMaxPath(Node * root);
22 int max(int, int);
23 
24 /* Drive for */
25 int main(){
26     Node * root = buildTree();
27     cout << findMaxPath(root);
28     return 0;
29 }
30 
31 /* Utility function to build a tree */
32 Node * buildTree(){
33     int height=1;
34     cin >> height;
35 
36     // Make space to hold the value
37     Node ** temp=new Node *[height];
38     for (int i = 0; i < height; i++){
39         temp[i] = new Node[i + 1];         // for every column, use a pointer to access the elements
40         for (int j = 0; j <= i; j++){
41             cin >> temp[i][j].data;
42             temp[i][j].left = NULL;
43             temp[i][j].right = NULL;        // Intilize the pointers 
44         }        
45     }
46         
47     // To link the elements, make pointers point their children
48     for (int i = 0; i<height-1; i++){
49         for (int j = 0; j <= i; j++){
50             temp[i][j].left = &temp[i + 1][j];
51             temp[i][j].right = &temp[i + 1][j + 1];
52         }
53     }
54 
55     return temp[0];                        // return the root node's adress
56 }
57 
58 /* Utility function to find the max path, and return the final cost */
59 int findMaxPath(Node * root){
60     if (root==NULL)               // Intilize the pointer before using it.
61         return 0;
62         
63     int Max = max(findMaxPath(root->left), findMaxPath(root->right));
64     return (root->data + Max);        
65 }
66 
67 /* Get the larger value from two inputs */
68 int max(int a, int b){
69     if (a<b)
70         return b;
71     else
72         return a;
73 }
View Code

 

编写代码中出现的问题:

  由于之前很久没有用c++,就把c++中一些基本而重要的概念忘记了。例如,在创建一个变量的时候,一定要适当地将它初始化,否则很容易出现运行时错误。特别是指针,由于它直接访问内存,若没有很好的处理,很容易就早成程序意外地终止。在编写这个程序中,我就不幸遇到这个问题,由于没有初始化节点的左右指针,出现了无法读取内存的运行时错误,导致自己调试了很久都没明白错误的来源(ps,也可能自己水平还不够吧)。因为个人觉得这个教训比较重要,在此记录该错误,希望以后能引以为鉴。

 

用VS2013调试:      

注释掉初始化子节点的左右指针:

 

测试代码:

程序能启动运行

 

输入数据后运行中断:

 

调试代码发现:

当访问到叶子节点的指针时出现了错误,data=???,left=???,right=???

 

最后,去掉注释后,在dos窗口下用g++编译能正常运行:

 

  • OJ

  推荐一个在线OJ的网站(OJ是Online Judge系统的简称,用来在线检测程序源代码的正确性)

  https://leetcode.com/ 

 

posted @ 2015-05-24 11:19  artificerpi  阅读(726)  评论(0编辑  收藏  举报

Copyright ©2017 artificerpi