如下图是一个数塔,从顶部出发在每一个节点可以选择向左或者向右走,一直走到底层,要求找出一条路径,使得路径上的数字之和最大.
数塔问题
1.搜索
#include<iostream>
using namespace std;
const int maxn=1005;
int a[maxn][maxn],curr,ans,n;
void dfs(int x,int y,int curr)//定义递归函数
{
if(x==n)//如果x==n,则退出;否则继续递归x+1,y和x+1,y+1
{
if(curr>ans) ans=curr;
return;
}
dfs(x+1,y,curr+a[x+1][y]);
dfs(x+1,y+1,curr+a[x+1][y+1]);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i=i+1)
for(int j=1;j<=i;j=j+1)
cin>>a[i][j];
dfs(1,1,a[1][1]);
cout<<ans<<endl;
return 0;
}
以上算法有的路径会重复搜索,每条路都有2个可能性,时间复杂度o(2~n-1),超时!!!
2.记忆化搜索
#include<iostream>
using namespace std;
const int maxn=1005;
int a[maxn][maxn],f[maxn][maxn],n;
int fs(int x,int y)
{
if(f[x][y]==-1)//如果这个元素没被计算过,则继续;如果算过,则直接返回它的值
{
if(x==n) f[x][y]=a[x][y];//如果x!=n,则继续调用递归函数
else f[x][y]=max(fs(x+1,y),fs(x+1,y+1))+a[x][y];
}
return f[x][y];
}
int main()
{
cin>>n;
for(int i=1;i<=n;i=i+1)
for(int j=1;j<=i;j=j+1)
cin>>a[i][j];
for(int i=1;i<=n;i=i+1)
for(int j=1;j<=i;j=j+1)
f[i][j]=-1;
fs(1,1);
cout<<f[1][1]<<endl;
return 0;
}
3.动态规划的状态转移方程
#include <iostream>
using namespace std;
const int maxn=1005;
int a[maxn][maxn],f[maxn][maxn];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i=i+1)
for(int j=1;j<=i;j=j+1)
cin>>a[i][j];
f[1][1]=a[1][1];
for(int i=2;i<=n;i=i+1)
for(int j=1;j<=i;j=j+1)
f[i][j]=max(f[i-1][j],f[i-1][j-1])+a[i][j];//状态转移方程
int ans=0;
for(int i=1;i<=n;i=i+1)
ans=max(ans,f[n][i]);
cout<<ans<<endl;
return 0;
}