洛谷 P1216 数字三角形(dp)

本文针对一道经典的动态规划问题进行解析,介绍了从下至上递推的方法,通过实例代码演示了如何求解数字金字塔中路径的最大和。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一道经典的DP
题目链接:https://www.luogu.org/problemnew/show/P1216
题目描述
观察下面的数字金字塔。

写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。

输入输出格式
输入格式
第一个行包含 R(1<= R<=1000) ,表示行的数目。

后面每行为这个数字金字塔特定行包含的整数。

所有的被供应的整数是非负的且不大于100。

输出格式
单独的一行,包含那个可能得到的最大的和。

输入输出样例
输入样例#1:

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

输出样例#1:

30

此题有很多写法,这里只介绍一种。。。
主要思路是从下往上递推,假设现在n-1层,往上的n-2层就由n-1层的两个数决定,哪个大加哪个,并改变n-2层的赋值,这样一直改变上去直到1号节点。
上代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n;
int a[1005][1005];
int main(){
    int i,j;
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        for(j=1;j<=i;j++){
            scanf("%d",&a[i][j]);
        }
    }
    for(i=n-1;i>=1;i--){
        for(j=1;j<=i;j++){
            int p1=a[i][j]+a[i+1][j];
            int p2=a[i][j]+a[i+1][j+1];
            a[i][j]=max(p1,p2);//选取最大的
        }
    }
    printf("%d",a[1][1]);
return 0;
}

总结:dp问题重要的是状态转移

### 洛谷 P1284 三角形牧场 题目描述 奶牛们希望设计一种新的牧场形状——由漂亮的白色栅栏围成的三角形牧场。建筑师 Hei 手中有 $n$ 块木板,每块木板的长度为整数值 $l_i$。她的目标是利用这些木板拼接出一个能够形成合法三角形的最大面积牧场。 #### 输入格式 输入的第一行为一个正整数 $n$ ($3 \leq n \leq 15$),代表拥有的木板数量;第二行为 $n$ 个正整数 $l_1, l_2, ..., l_n$ ($1 \leq l_i \leq 10^6$),分别表示各木板的长度。 #### 输出格式 如果无法构成任何三角形,则输出 `-1`;否则输出能组成的最大面积,保留两位小数。 --- ### 解法分析 此问题的核心在于如何通过给定的木板组合找到满足三角形条件的最佳方案并计算其面积。以下是两种主要方法: #### 方法一:动态规划 (DP) 定义状态 `dp[i][j]` 表示前 $i$ 条边中是否存在两条边分别为 $j$ 和 $c-j-k$ 的情况,其中 $c=\sum_{k=1}^{n}{l_k}$ 是总周长的一半[^2]。转移方程如下: ```cpp if ((j - l[i] >= 0 && dp[j - l[i]][k]) || (k - l[i] >= 0 && dp[j][k - l[i]])) dp[j][k] = true; ``` 最终判断是否能找到三个符合条件的边 $(a,b,c)$ 并验证它们是否可构成三角形: ```cpp inline bool check(int a, int b, int c) { if (a + b > c && a + c > b && b + c > a) return true; return false; } check(i, j, c - i - j); ``` 一旦确认存在这样的三边组合,即可应用 **海伦公式** 计算面积: $$ S = \sqrt{p(p-a)(p-b)(p-c)} $$ 其中 $ p = \frac{a+b+c}{2} $ 是半周长。 --- #### 方法二:搜索算法 另一种解法基于暴力搜索的思想,但由于直接穷举所有可能性会导致超时(TLE),因此需引入剪枝策略优化效率[^4]。具体实现步骤包括但不限于以下几个方面: - 对原始数组按升序排列; - 枚举当前尝试加入哪条边上; - 使用回溯技术逐步试探直至完成分配过程; - 结合均值不等式的理论依据进一步缩小候选范围,即倾向于让三条边尽可能接近从而提升潜在最优解的概率。 下面是简化版伪代码展示这一逻辑框架: ```python def dfs(index, sideA, sideB, sideC): global maxArea # 边界处理与更新最佳结果记录 currentPerimeter = sideA + sideB + sideC semiPerimeter = currentPerimeter / 2 areaCandidate = sqrt(semiPerimeter*(semiPerimeter-sideA)*(semiPerimeter-sideB)*(semiPerimeter-sideC)) if isValid(sideA, sideB, sideC): if areaCandidate > maxArea: maxArea = areaCandidate # 继续探索剩余选项 for nextIndex in range(index+1, lengthOfPlanks): newLength = lengths[nextIndex] # 分配至不同边缘之一 dfs(nextIndex, sideA + newLength, sideB , sideC ) dfs(nextIndex, sideA , sideB + newLength, sideC ) dfs(nextIndex, sideA , sideB , sideC + newLength ) # 初始化调用入口函数 maxArea = -1 dfs(-1, 0, 0, 0) print("%.2f"%maxArea if maxArea != -1 else "-1") ``` 注意此处仅提供概念示意而非完整可用程序片段。 --- ### 海伦公式的实际运用实例 假设已知某组数据样本 $\{7, 9, 12\}$ 可成功构建有效三角形,则对应操作流程如下所示: 设 $s=(7+9+12)/2=14$ 代入得 $$ A=\sqrt{s(s−a)(s−b)(s−c)}=\sqrt{14(14−7)(14−9)(14−12)}≈26.83 $$ ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值