数塔(HDU 2084)【记忆化搜索】/【DP递推】

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2084
题目大意:就是一个数塔,从头走到顶,问路径最大的和是多少。

题解:
如果我们搜索所有路径,一共有2^n-1种路径,时间复杂度太大了。
或者我们直接用递归,还是会重复走一些结点,要走的结点一共有2^n-1个,跟搜索所有路径是一样的。
所以考虑下面两种方法。

前话:dp [ i ] [ j ]是数塔上(i,j)位置处往下的其中一条路径所能实现的最大和,最终我们要的结果是dp[1][1]

**【记忆化搜索】**O(n^2)
为了防止dp[i][j]多次被调用,所以我们将它初始化为-1.
在调用函数的时候,判断dp[i][j]是否为负数,负数是没有跑过的,正数就是已经跑过的,所以dp在这里还用来记忆了是否走过该结点。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define P(x) x>0?x:0
#define INF 0x3f3f3f3f

using namespace std;
typedef long long ll;
typedef vector<int>:: iterator VITer;
const int maxN=105;

int dp[maxN][maxN];
int a[maxN][maxN];
int N;

void init()
{
    memset(dp,-1, sizeof(dp));
}

int solve(int i,int j)//就是找到(i,j)位置往下(数塔下面)的最大和
{
    if(dp[i][j]>=0)//记忆化搜索,dp初始化为-1,如果不是-1的话说明搜过了已经,所以直接返回值就可以了
        return dp[i][j];
    else
        return dp[i][j]=a[i][j]+(i==N? 0 : max(solve(i+1,j),solve(i+1,j+1) ) );//注意更新dp[i][j]的值
}

int main()
{
    int C;
    scanf("%d",&C);
    while(C--)
    {
        scanf("%d",&N);
        for(int i=1;i<=N;i++)
        {
            for(int j=1;j<=i;j++)
            {
                scanf("%d",&a[i][j]);
            }
        }
        init();
        printf("%d\n",solve(1,1));
    }
    return 0;
}

**【DP递推】**O(n^2)
我们从最后一行开始往上找最佳路径。容易得出状态转化方程为
dp[i][j]=a[i][j]+(i==N ? 0 : max(dp[i+1][j],dp[i+1][j+1]))
如果是最后一行的话,直接就是对应位置上的值,如果是1->(n-1)行的话就是直接比较i+1行的相邻两项的dp值,取较大者,一直到最后。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define P(x) x>0?x:0
#define INF 0x3f3f3f3f

using namespace std;
typedef long long ll;
typedef vector<int>:: iterator VITer;
const int maxN=105;

int dp[maxN][maxN];
int a[maxN][maxN];
int N;

int main()
{
    int C;
    scanf("%d",&C);
    while(C--)
    {
        scanf("%d",&N);
        for(int i=1;i<=N;i++)
        {
            for(int j=1;j<=i;j++)
            {
                scanf("%d",&a[i][j]);
            }
        }
        for(int i=N;i>=1;i--)
        {
            for(int j=1;j<=i;j++)
            {
                dp[i][j]=a[i][j]+(i==N ? 0 : max(dp[i+1][j],dp[i+1][j+1]));
            }
        }
        printf("%d\n",dp[1][1]);
    }
    return 0;
}

你可能感兴趣的:(#,基本DP,动态规划)