dp入门题(数塔)

http://acm.hdu.edu.cn/showproblem.php?pid=2084

题意:

        7
      3      8
    8     1       0
  2       7     4       4
4    5    2       6        5

 

在上面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大。
路径上的每一步都只能往左下或右下走。只需要求出这个最大和即可,不必给出具体路径。
 
解法1:dfs搜索每一条路径,可以发现很多点会重复搜索。时间复杂度为:O(2的n次方)
//#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include
#include 
#define ME(x , y) memset(x , y , sizeof(x))
#define SF(n) scanf("%d" , &n)
#define rep(i , n) for(int i = 0 ; i < n ; i ++)
#define INF  0x3f3f3f3f
#define mod 20191117
#define PI acos(-1)
using namespace std;
typedef long long ll ;
int a[109][109];
int n ;

int getsum(int i , int j)
{
    if(i == n)
        return a[i][j];
    else{
        int x = getsum(i+1 , j);
        int y = getsum(i+1 , j+1);
        return max(x , y) + a[i][j];
    }
}

int main()
{
    /*#ifdef ONLINE_JUDGE
    #else
        freopen("D:/c++/in.txt", "r", stdin);
        freopen("D:/c++/out.txt", "w", stdout);
    #endif*/
    int t ;
    scanf("%d" , &t);
    while(t--)
    {
        memset(dp , -1 , sizeof(dp));
        scanf("%d" , &n);
        for(int i = 1 ; i <= n ; i++)
        {
            for(int j = 1 ; j <= i ; j++)
            {
                scanf("%d" , &a[i][j]);
            }
        }
        cout << getsum(1 , 1) << endl ;

    }


    return 0;
}

解法1改进:记忆化搜索,将搜索过的点记录下来。时间复杂度O(n的平方)。

//#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include
#include 
#define ME(x , y) memset(x , y , sizeof(x))
#define SF(n) scanf("%d" , &n)
#define rep(i , n) for(int i = 0 ; i < n ; i ++)
#define INF  0x3f3f3f3f
#define mod 20191117
#define PI acos(-1)
using namespace std;
typedef long long ll ;
int a[109][109];
int n ;
int dp[109][109];


int getsum(int i , int j)
{
    if(i == n)
        return a[i][j];
    else{
        if(dp[i][j] != -1) return dp[i][j];
        int x = getsum(i+1 , j);
        int y = getsum(i+1 , j+1);
        dp[i][j] = max(x,y)+a[i][j];
        return max(x , y) + a[i][j];
    }
    return dp[i][j] ;
}


int main()
{
    /*#ifdef ONLINE_JUDGE
    #else
        freopen("D:/c++/in.txt", "r", stdin);
        freopen("D:/c++/out.txt", "w", stdout);
    #endif*/
    int t ;
    scanf("%d" , &t);
    while(t--)
    {
        memset(dp , -1 , sizeof(dp));
        scanf("%d" , &n);
        for(int i = 1 ; i <= n ; i++)
        {
            for(int j = 1 ; j <= i ; j++)
            {
                scanf("%d" , &a[i][j]);
            }
        }
        cout << getsum(1 , 1) << endl ;
    }


    return 0;
}

 

解法2、递归转为递推。从底层向上递推。

//#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include
#include 
#define ME(x , y) memset(x , y , sizeof(x))
#define SF(n) scanf("%d" , &n)
#define rep(i , n) for(int i = 0 ; i < n ; i ++)
#define INF  0x3f3f3f3f
#define mod 20191117
#define PI acos(-1)
using namespace std;
typedef long long ll ;
int a[109][109];
int n ;
int dp[109][109];



int main()
{
    /*#ifdef ONLINE_JUDGE
    #else
        freopen("D:/c++/in.txt", "r", stdin);
        freopen("D:/c++/out.txt", "w", stdout);
    #endif*/
    int t ;
    scanf("%d" , &t);
    while(t--)
    {
        memset(dp , -1 , sizeof(dp));
        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 = 1 ; i <= n ; i++)
        {
            dp[n][i] = a[n][i];
        }
        for(int i = n - 1 ; i >= 1 ; i--)
        {
            for(int j = 1 ; j <= i ; j++)
            {
                dp[i][j] = max(dp[i+1][j] , dp[i+1][j+1])+a[i][j];
            }
        }
        cout << dp[1][1] << endl ;
    }


    return 0;
}

 

 

解法2优化空间

//#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include
#include 
#define ME(x , y) memset(x , y , sizeof(x))
#define SF(n) scanf("%d" , &n)
#define rep(i , n) for(int i = 0 ; i < n ; i ++)
#define INF  0x3f3f3f3f
#define mod 20191117
#define PI acos(-1)
using namespace std;
typedef long long ll ;
int a[109][109];
int n ;
int dp[109];


int main()
{
    /*#ifdef ONLINE_JUDGE
    #else
        freopen("D:/c++/in.txt", "r", stdin);
        freopen("D:/c++/out.txt", "w", stdout);
    #endif*/
    int t ;
    scanf("%d" , &t);
    while(t--)
    {
        memset(dp , -1 , sizeof(dp));
        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 = 1 ; i <= n ; i++)
        {
            dp[i] = a[n][i];
        }
        for(int i = n - 1 ; i >= 1 ; i--)
        {
            for(int j = 1 ; j <= i ; j++)
            {
                dp[j] = max(dp[j] , dp[j+1])+a[i][j];
            }
        }
        cout << dp[1] << endl ;
    }


    return 0;
}

 

 

你可能感兴趣的:(dp入门题(数塔))