背景 Background
在很久很久以前,有一个动物村庄,那里是猪的乐园(^_^),村民们勤劳、勇敢、善良、团结……
不过有一天,最小的小小猪生病了,而这种病是极其罕见的,因此大家都没有储存这种药物。所以晴天小猪自告奋勇,要去采取这种药草。于是,晴天小猪的传奇故事便由此展开……
描述 Description
这一天,他来到了一座深山的山脚下,因为只有这座深山中的一位隐者才知道这种药草的所在。但是上山的路错综复杂,由于小小猪的病情,晴天小猪想找一条需时最少的路到达山顶,但现在它一头雾水,所以向你求助。
山用一个三角形表示,从山顶依次向下有1段、2段、3段等山路,每一段用一个数字T(1<=T<=100)表示,代表晴天小猪在这一段山路上需要爬的时间,每一次它都可以朝左、右、左上、右上四个方向走(**注意**:在任意一层的第一段也可以走到本层的最后一段或上一层的最后一段)。
晴天小猪从山的左下角出发,目的地为山顶,即隐者的小屋。
输入格式 Input Format
第一行有一个数n(2<=n<=1000),表示山的高度。
从第二行至第n+1行,第i+1行有i个数,每个数表示晴天小猪在这一段山路上需要爬的时间。
输出格式 Output Format
一个数,即晴天小猪所需要的最短时间。
在很久很久以前,有一个动物村庄,那里是猪的乐园(^_^),村民们勤劳、勇敢、善良、团结……
不过有一天,最小的小小猪生病了,而这种病是极其罕见的,因此大家都没有储存这种药物。所以晴天小猪自告奋勇,要去采取这种药草。于是,晴天小猪的传奇故事便由此展开……
描述 Description
这一天,他来到了一座深山的山脚下,因为只有这座深山中的一位隐者才知道这种药草的所在。但是上山的路错综复杂,由于小小猪的病情,晴天小猪想找一条需时最少的路到达山顶,但现在它一头雾水,所以向你求助。
山用一个三角形表示,从山顶依次向下有1段、2段、3段等山路,每一段用一个数字T(1<=T<=100)表示,代表晴天小猪在这一段山路上需要爬的时间,每一次它都可以朝左、右、左上、右上四个方向走(**注意**:在任意一层的第一段也可以走到本层的最后一段或上一层的最后一段)。
晴天小猪从山的左下角出发,目的地为山顶,即隐者的小屋。
输入格式 Input Format
第一行有一个数n(2<=n<=1000),表示山的高度。
从第二行至第n+1行,第i+1行有i个数,每个数表示晴天小猪在这一段山路上需要爬的时间。
输出格式 Output Format
一个数,即晴天小猪所需要的最短时间。
也是一个动态规划的问题,但是自己对于动态规划的理解还是不够,各种窘迫,又一次不得不去参看别人的代码,由于自己水平比较低下,好多别人的代码都理解不了, 有些效率高的代码设计的很精巧,理解起来也极为困难,与之相对,一些容易理解的代码的效率也就不是很高了。最后自己找了一个暴力DP的思想来求解这个问题,期间的问题也是多多,各种被卡,直到很晚,才在博客园一位大牛的博客的启发下修改正确,这个问题将会着重讨论。动态规划啊,啥时候能有点感觉啊……
仍然无耻的把自己的代码贴出来。
#include <stdio.h>
//#include <Windows.h>
int a[1001][1001];
long int step[1001][1001];
int main()
{
int n,i,j,flag = 0;
scanf("%d",&n);
for (i=1;i<=n;i++)
{
for(j=1;j<=i;j++)
{
scanf("%d",&a[i][j]);
step[i][j] = 100000;
}
}
step[1][0] = a[1][1];
step[1][2] = a[1][1];
for (i=2;i<=n;i++)
{
while(1)
{
step[i][0] = step[i][i];
step[i][i+1] = step[i][1];
flag = 1;
for (j=1;j<=i;j++)
{
//
if (step[i][j]>step[i-1][j]+a[i][j])
{
step[i][j] = step[i-1][j]+a[i][j];
flag = 0;
}
if (step[i][j]>step[i-1][j-1]+a[i][j])
{
step[i][j] = step[i-1][j-1]+a[i][j];
flag = 0;
}
if (step[i][j]>step[i][j-1]+a[i][j])
{
step[i][j] = step[i][j-1]+a[i][j];
flag = 0;
}
if (step[i][j]>step[i][j+1]+a[i][j])
{
step[i][j] = step[i][j+1]+a[i][j];
flag = 0;
}
}
if (flag == 1)
break;
}
}
printf("%ld",step[n][1]);
//system("pause");
return 0;
}
备注:
- 首先就是对于题意的理解出现了问题,题目表述不清楚,走的四个方向就把我整晕了,左右好理解,左上右上是啥回事,后来才想明白是三角锥形的排列方式,如下图,每行数据还是圆形排列,就像一个圆锥。
本题可以采用自上而下或者自下而上两种方式来求解,我们采用自上而下的方式。根据上图的排列我们可构造出动态规划方程
step[i][j] = min{step[i][j-1]+a[i][j],step[i][j+1]+a[i][j],step[i-1][j-1]+a[i][j],step[i][j]+a[i][j]} - 在程序实现的过程中一再的报错,提示stack overflow,昨天的青蛙过河是由于递归层次太多导致堆栈溢出,这个程序也没有10^9这么大的数据,递归也没有用到,问题最后归结到了开篇那个数组身上,一开始将其声明为局部变量,后来改为全局变量程序才得以通过。原来windows32位操作系统给程序的栈、堆分配的空间默认为1M。我开辟的数组为step[1000][1000],假设为int类型的话,step占空间为4*1000*1000Byte 大约是3M多一点。出现越界也是必然的了。关于这个问题将会细致的讨论一下。参见文章程序中关于堆栈的划定。
总结:在写程序的时候要有空间观念,大小超过1M的变量尽量定义为全局变量或者静态变量。