1、直接用递归函数计算状态转移方程,效率十分低下,可以考虑用递推方法,其实就是“正着推导,逆着计算”
#include<iostream> #include<algorithm> using namespace std; #define maxn 1000+5 int n; int a[maxn][maxn]; int d[maxn][maxn]; int main(){ for(;cin>>n && n;){ memset(d,0,sizeof(d)); int i,j; for(i=1;i<=n;i++){ //输入 for(j=1;j<=i;j++){ cin>>a[i][j]; } } for(j=1;j<=n;j++){ //计算最底层d[][]值 d[n][j]=a[n][j]; } for(i=n-1;i>=1;i--){ //从下向上计算d[][]值 for(j=1;j<=i;j++){ d[i][j]=a[i][j]+max(d[i+1][j],d[i+1][j+1]); } } cout<<d[1][1]<<' '; } }
2、记忆化搜索虽然也是递归,但同时把计算结果保存在d[][]中,可以保证每个节点只访问一次(不必事先确定各状态计算顺序,但需要记录每个状态是否计算过,本题把d[][]初始为-1,>=0则算过。
#include<iostream> #include<algorithm> using namespace std; #define maxn 1000+5 int n; int a[maxn][maxn]; int d[maxn][maxn]; int D(int i,int j){ if(d[i][j]>=0)return d[i][j]; return d[i][j]=a[i][j]+(i==n ? 0 : max(D(i+1,j),D(i+1,j+1))); //记忆化搜索要保存每次计算结果 } int main(){ for(;cin>>n && n;){ memset(d,-1,sizeof(d)); //初始化为-1,也是为记忆化搜索做的标记,当>=0时直接返回d[][]; int i,j; for(i=1;i<=n;i++){ for(j=1;j<=i;j++){ cin>>a[i][j]; } } cout<<D(1,1)<<' '; } }