#401. 【dp开始】数字三角形
题目描述:
观察下面的数字金字塔。
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。
在上面的样例中,从7 到 3 到 8 到 7 到 5 的路径产生了最大。
主题思路:
这一题就是一道十分典型的DP(动态规划)思想的题目。我们也许会问,DP是什么???DP是一种思想,而不是一种算法,这与贪心是一个道理。DP也是通过一群局部最优解得到一个全局最优解,但也有求方案数的DP。DP与贪心不同,DP是需要划分阶段并写方程的。不过DP也有两种形式:递推与记忆化搜索(记忆化搜索一般常数较大,比较慢)。DP的具体思想都是要做题做出来的,所以得看题。DP一般要满足两个特性:最优性与无后效性。最优性即要满足最优解性质,保证每一步都是最优的。无后效性即要满足求解某个阶段只会与上一个阶段有关,或者说一个阶段求完后,不会对前面造成影响。划分阶段即设定数组,这个数组的某一位表示什么情况下的最优解,最终推得全局解。找出这个阶段与上一个阶段的关系,即如何从这个阶段的解推得下一个阶段解(以上对这一题来说其实都是废话)。
这一题就是要从金字塔的底层开始逆推,然后求出整体的全局最优解。真是道简单而典型的DP题目。这样说我们可能都不明白,我们来从题目样例操作一遍:
最顶层:7
第二层:3 8
第三层:8 1 0
第四层:2 7 4 4
最底层:4 5 2 6 5
从最底层第一个开始搜索,每次搜索a【i】【j】和a【i】【j+1】,从中选出一个较大数,并与a【i-1】【j】相加。就拿最底层第一个4来说吧,4和5比较,显然是5比较大,然后把第四层第一个2加上较大数5,得到了6。不断进行这种操作。最后得到一个“加工”过的数组如下:
最顶层:30
第二层:23 21
第三层:20 13 10
第四层:7 12 10 10
最底层:4 5 2 6 5
然后我们就会发现最顶层的那个数就是我们要得到的最大值,这就是本题的最优解。这题完全可以使用过程或者函数解决,但因为鄙人是小蒟蒻一只,并且这一题不用考虑会不会超内存,不用优化,所以我决定用上最简单粗暴的二重循环来解决这道DP。
代码如下:
#include<bits/stdc++.h>
using namespace std;
int a[1001][1001]={0},b[1001][1001]={0},i,j,r,t;
int main()
{
cin>>r;
for(i=1;i<=r;i++)
for(j=1;j<=i;j++)
cin>>a[i][j];
for(i=r-1;i>=1;i--)
for(j=1;j<=i;j++)
{
if(a[i+1][j]>a[i+1][j+1])t=a[i+1][j];
if(a[i+1][j]<a[i+1][j+1])t=a[i+1][j+1];
a[i][j]+=t;
}
cout<<a[1][1];
}然后我们就会惊奇的发现:居然没AC?!
然后仔细思考,如果比较的两个数相等,那么T就不会改变,所以应该再加一个IF语句判断是否相等。真让人头秃。。。。。。
终极程序:
#include<bits/stdc++.h>
using namespace std;
int a[1001][1001]={0},b[1001][1001]={0},i,j,r,t;//最好使用全局变量
int main()
{
cin>>r;
for(i=1;i<=r;i++)
for(j=1;j<=i;j++)
cin>>a[i][j];//读入是一个三角形方阵
for(i=r-1;i>=1;i--)
for(j=1;j<=i;j++)
{
if(a[i+1][j]>a[i+1][j+1])t=a[i+1][j];//判断哪个比较大
if(a[i+1][j]<a[i+1][j+1])t=a[i+1][j+1];//ctrl+c方便一点
if(a[i+1][j]==a[i+1][j+1])t=a[i+1][j+1];//判断是否相等
a[i][j]+=t;//上一层加上较大数
}
cout<<a[1][1];//输出最顶层的那一个数(全局最优解)
}
终于AC了,不容易啊!!!这真是道好题。。。DP就是要细心。。。#401. 【dp开始】数字三角形
题目描述:
观察下面的数字金字塔。
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。
在上面的样例中,从7 到 3 到 8 到 7 到 5 的路径产生了最大。
主题思路:
这一题就是一道十分典型的DP(动态规划)思想的题目。我们也许会问,DP是什么???DP是一种思想,而不是一种算法,这与贪心是一个道理。DP也是通过一群局部最优解得到一个全局最优解,但也有求方案数的DP。DP与贪心不同,DP是需要划分阶段并写方程的。不过DP也有两种形式:递推与记忆化搜索(记忆化搜索一般常数较大,比较慢)。DP的具体思想都是要做题做出来的,所以得看题。DP一般要满足两个特性:最优性与无后效性。最优性即要满足最优解性质,保证每一步都是最优的。无后效性即要满足求解某个阶段只会与上一个阶段有关,或者说一个阶段求完后,不会对前面造成影响。划分阶段即设定数组,这个数组的某一位表示什么情况下的最优解,最终推得全局解。找出这个阶段与上一个阶段的关系,即如何从这个阶段的解推得下一个阶段解(以上对这一题来说其实都是废话)。
这一题就是要从金字塔的底层开始逆推,然后求出整体的全局最优解。真是道简单而典型的DP题目。这样说我们可能都不明白,我们来从题目样例操作一遍:
最顶层:7
第二层:3 8
第三层:8 1 0
第四层:2 7 4 4
最底层:4 5 2 6 5
从最底层第一个开始搜索,每次搜索a【i】【j】和a【i】【j+1】,从中选出一个较大数,并与a【i-1】【j】相加。就拿最底层第一个4来说吧,4和5比较,显然是5比较大,然后把第四层第一个2加上较大数5,得到了6。不断进行这种操作。最后得到一个“加工”过的数组如下:
最顶层:30
第二层:23 21
第三层:20 13 10
第四层:7 12 10 10
最底层:4 5 2 6 5
然后我们就会发现最顶层的那个数就是我们要得到的最大值,这就是本题的最优解。这题完全可以使用过程或者函数解决,但因为鄙人是小蒟蒻一只,并且这一题不用考虑会不会超内存,不用优化,所以我决定用上最简单粗暴的二重循环来解决这道DP。
代码如下:
#include<bits/stdc++.h>
using namespace std;
int a[1001][1001]={0},b[1001][1001]={0},i,j,r,t;
int main()
{
cin>>r;
for(i=1;i<=r;i++)
for(j=1;j<=i;j++)
cin>>a[i][j];
for(i=r-1;i>=1;i--)
for(j=1;j<=i;j++)
{
if(a[i+1][j]>a[i+1][j+1])t=a[i+1][j];
if(a[i+1][j]<a[i+1][j+1])t=a[i+1][j+1];
a[i][j]+=t;
}
cout<<a[1][1];
}然后我们就会惊奇的发现:居然没AC?!
然后仔细思考,如果比较的两个数相等,那么T就不会改变,所以应该再加一个IF语句判断是否相等。真让人头秃。。。。。。
终极程序:
#include<bits/stdc++.h>
using namespace std;
int a[1001][1001]={0},b[1001][1001]={0},i,j,r,t;//最好使用全局变量
int main()
{
cin>>r;
for(i=1;i<=r;i++)
for(j=1;j<=i;j++)
cin>>a[i][j];//读入是一个三角形方阵
for(i=r-1;i>=1;i--)
for(j=1;j<=i;j++)
{
if(a[i+1][j]>a[i+1][j+1])t=a[i+1][j];//判断哪个比较大
if(a[i+1][j]<a[i+1][j+1])t=a[i+1][j+1];//ctrl+c方便一点
if(a[i+1][j]==a[i+1][j+1])t=a[i+1][j+1];//判断是否相等
a[i][j]+=t;//上一层加上较大数
}
cout<<a[1][1];//输出最顶层的那一个数(全局最优解)
}
终于AC了,不容易啊!!!这真是道好题。。。DP就是要细心。。。