zoukankan      html  css  js  c++  java
  • 数塔 HDU 2084

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

    https://vjudge.net/contest/342215#problem/D

    题目描述:

    数塔

    Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 73975    Accepted Submission(s): 42708


    Problem Description
    在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的:
    有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?

    已经告诉你了,这是个DP的题目,你能AC吗?
     
    Input
    输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数,且所有的整数均在区间[0,99]内。
     
    Output
    对于每个测试实例,输出可能得到的最大和,每个实例的输出占一行。
     
    Sample Input
    1
    5
    7
    3 8
    8 1 0
    2 7 4 4
    4 5 2 6 5
     
    Sample Output
    30
     

    解题思路:

    对于这道题,我们很容易能够想到用递归自顶向下的思想来求解。因为对于每一个数,从它往下走的话只能走向它的正下或是右下(对于输入的样例来说),所以我们可以递归每个数能够达到的最优解然后把它反馈给(1,1)。
    当达到最末的位置时(即i==n)返回 dp[i][j],否则就找其下方的最大的那个值,然后把它加起来。
     1 #include <bits/stdc++.h>
     2 
     3 #define N 100010
     4 
     5 using namespace std;
     6 
     7 typedef long long int ll;
     8 
     9 /*******************
    10 (1,1)
    11 (2,1) (2,2)
    12 (3,1) (3,2) (3,3)
    13 (4,1) (4,2) (4,3) (4,4)
    14 ********************/
    15 
    16 int n;
    17 int dp[110][110]={0};
    18 int max_num(int i, int j){
    19     if(i==n) return dp[i][j];   //递归出口
    20     else return dp[i][j]+max(max_num(i+1, j), max_num(i+1, j+1)); //求当前位置的最优解
    21 }
    22 
    23 int main()
    24 {
    25     int c;
    26     cin>>c;
    27     while(c--){
    28         int i, j;
    29         cin>>n;
    30         for(i=1; i<=n; i++){
    31             for(j=1; j<=i; j++){
    32                 cin>>dp[i][j];
    33             }
    34         }
    35         cout<<max_num(1, 1)<<'
    ';
    36     }
    37     return 0;
    38 }

    显然,递归的效率在这里很低,由于我们需要对每个数向下两分支查找,当我们处于dp[i][j]时,我们会对(i+1 , j)和(i+1 , j+1)向下进行一次搜索,而当在dp[i][j+1]时,又对(i+1, j+1)进行了一次搜索,所以我们能想到,如果把(i+1, j+1)的结果记录下来,那么就能减少一些搜索的时间,而且,可以大大降低降低原来为Ο(2n)的时间复杂度。因为改变后,我们需要进行的操作数就只有1+2+3+……+n=(n2-n)/2,时间复杂度为Ο(n2)。

    所以我们可以得到动态转移方程 dp[i][j]=a[i][j]+max(dp[i+1][j], dp[i+1][j+1])。

    代码如下:
     1 #include <iostream>
     2 #include <algorithm>
     3 #include <cstdio>
     4 #include <cstdlib>
     5 
     6 #define N 100010
     7 
     8 using namespace std;
     9 
    10 typedef long long int ll;
    11 
    12 /*******************
    13 (1,1)
    14 (2,1) (2,2)
    15 (3,1) (3,2) (3,3)
    16 (4,1) (4,2) (4,3) (4,4)
    17 ********************/
    18 
    19 int main()
    20 {
    21     int a[110][110];
    22     int c;
    23     int n;
    24     scanf("%d", &c);
    25     while(c--){
    26         int i, j;
    27         int dp[200][200]={0};
    28         scanf("%d", &n);
    29         for(i=1; i<=n; i++){
    30             for(j=1; j<=i; j++){
    31                 scanf("%d", &a[i][j]);
    32             }
    33         }
    34         for(i=n; i>=1; i--){    //从后往前
    35             for(j=1; j<=n; j++){
    36                 dp[i][j]=a[i][j]+max(dp[i+1][j], dp[i+1][j+1]);   //将到a[i][j]的最优解存到dp[i][j]中
    37             }
    38         }
    39         printf("%d
    ", dp[1][1]);
    40     }
    41     return 0;
    42 }
  • 相关阅读:
    从输入网址到页面呈现的过程
    Git 常用命令合集
    Jquery浅克隆与深克隆
    CSS变量教程
    设计模式
    Servlet和JSP简述
    SQL Server,MySQL,Oracle三者的区别
    mysql事务处理
    计时器
    java中length,length(),size()区别
  • 原文地址:https://www.cnblogs.com/Arrokoth/p/12053219.html
Copyright © 2011-2022 走看看