P1775 石子合并(弱化版)
感觉 dp 太难了,这真的感觉太难学了,但是还要写题记积累啊,唉!
感觉不用讲题意了(那你也别讲题解了)就是石子之间可以合并,合并的代价是这堆石子数,问如何合并全部石子后总代价最小。
考虑用区间 dp,设状态为 \(dp[i][j]\) 为区间 \([i,j]\) 的最小代价,转移时先枚举区间长度,然后枚举区间右端点,一个长度大于等于2的区间可以分为左右小区间,所以再枚举中间点分为左右区间,得到转移方程:
\(dp[j][r]=min(dp[j][r],dp[j][k]+dp[k+1][r]+s[j][r]);\)
最后答案就是 \(dp[1][n]\)。
合并代价就是区间和,所以可以用前缀和优化。
#include<bits/stdc++.h> using namespace std; int n; // 序列长度 int dp[305][305]; // 动态规划表,dp[i][j]表示将区间[i, j]合并为一段的最小代价 int s[305]; // 前缀和数组,s[i]表示前i个元素的和,用于快速计算区间和 int a[305]; // 存储输入的序列 int main(){ ios::sync_with_stdio(false); // 加速输入输出,避免C++的流式IO同步 cin >> n; // 读取序列长度 memset(dp,0x3f,sizeof dp); // 初始化动态规划表,0x3f3f3f3f是一个很大的数,相当于无穷大 for(int i = 1; i <= n; i++){ cin >> a[i]; // 读取序列中的元素 dp[i][i] = 0; // 初始化dp表,当区间[i, i]只有一个元素时,合并代价为0 s[i] = s[i-1] + a[i]; // 计算前缀和,用于快速获取任意区间的元素和 } // 动态规划部分 for(int len = 2; len <= n; len++){ // len是当前处理的子区间长度,逐渐从2增加到n for(int i = 1; i <= n - len + 1; i++){ // i是子区间的起始位置 int r = i + len - 1; // r是子区间的结束位置 for(int k = i; k < r; k++){ // 枚举分割点k,将[i, r]分成[i, k]和[k+1, r]两部分 dp[i][r] = min(dp[i][r], dp[i][k] + dp[k+1][r] + s[r] - s[i-1]); // 合并代价为子区间[i, k]和[k+1, r]的合并代价之和,再加上区间[i, r]的总和 } } } cout << dp[1][n]; // 输出整个序列[1, n]的最小合并代价 return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」