当前位置:首页 > 洛谷 > 洛谷2112题:用动态规划思想解决字符串分割

洛谷2112题:用动态规划思想解决字符串分割

7个月前 (08-19)

洛谷2112题:用动态规划思想解决字符串分割 前缀和 字符串 动态规划 洛谷题解 C++ 第1张

一、题目解读

洛谷P2112题要求将N个字符串分割为K行,使各行字符总数方差最小。输入包含N个字符串及目标行数K,需输出最小方差除以K的数值(保留一位小数)。题目难点在于高效计算分割方案,需平衡时间复杂度与精度要求。

二、解题思路

动态规划(DP)求解。核心思想:将问题拆解为“前i个字符串分成j行的最小方差”,利用前缀和优化累计字符数计算,通过状态转移方程递归求解最优解。关键步骤包括预处理、DP状态定义与转移、方差计算。

三、解题步骤

1. 输入与边界处理:读取N、K及字符串长度,若N=0、K=0或K>N直接输出0。

2. 前缀和预处理:构建prefix数组,存储前i个字符串的总长度,减少重复计算。

3. 动态规划初始化:定义dp[i][j]为前i个字符串分成j行的最小方差,初始化dp[0][0]=0。

4. 状态转移:外层循环i遍历字符串数,内层循环j遍历行数,通过k(分割点)枚举子问题,计算当前行字符总数与平均值的偏差平方,更新dp[i][j]=min(dp[k][j-1]+var)。

5. 输出结果:最终解为dp[N][K],除以K并格式化输出。

四、代码与注释

#include <iostream>
#include <vector>
#include <cmath>
#include <climits>
#include <iomanip>
#include <algorithm>
using namespace std;

const double INF = 1e18; // 定义无穷大,用于初始化DP值

int main() {
    int N, K;
    cin >> N >> K;
    
    // 处理特殊情况
    if (N == 0 || K == 0 || K > N) {
        cout << "0.0" << endl;
        return 0;
    }
    
    vector<int> lens(N); // 存储各字符串长度
    for (int i = 0; i < N; ++i) {
        string s;
        cin >> s;
        lens[i] = s.size();
    }
    
    vector<int> prefix(N+1, 0); // 前缀和数组
    for (int i = 1; i <= N; ++i) {
        prefix[i] = prefix[i-1] + lens[i-1];
    }
    
    // dp[i][j]: 前i个单词分成j行的最小方差和
    vector<vector<double>> dp(N+1, vector<double>(K+1, INF));
    dp[0][0] = 0;
    
    double avg = (double)prefix[N] / K; // 总字符数的平均值
    
    for (int i = 1; i <= N; ++i) {
        for (int j = 1; j <= min(K, i); ++j) {
            for (int k = j-1; k < i; ++k) {
                int sum = prefix[i] - prefix[k]; // 当前行字符总数
                double var = pow(sum - avg, 2); // 方差计算
                dp[i][j] = min(dp[i][j], dp[k][j-1] + var); // 状态转移
            }
        }
    }
    
    cout << fixed << setprecision(1) << dp[N][K]/K << endl; // 输出结果,保留1位小数
    return 0;
}

五、总结

1. 算法核心:动态规划通过子问题最优解推导全局最优,结合前缀和降低时间复杂度。

2. 优化点:状态转移方程的三层循环可通过斜率优化等方法进一步提速,但本题数据范围允许朴素DP。

3. 实际应用:适用于需要平衡分组差异的场景,如资源分配、任务调度等。

4. 注意事项:边界条件(如K>N)需提前判断,方差计算需注意浮点数精度。


原创内容 转载请注明出处

分享给朋友:

相关文章

力扣654:递归分治的艺术 如何用最大元素构建二叉树

力扣654:递归分治的艺术 如何用最大元素构建二叉树

题目重解我们面对一个看似简单却充满递归魅力的题目:给定一个不含重复元素的整数数组,需要构建一棵特殊的二叉树。这个树的每个父节点都必须是当前子数组中的最大元素,而它的左右子树则分别由该最大值左侧和右侧的...

GESP2023年六级真题解析:动态规划解决小杨买饮料问题(洛谷3873)

GESP2023年六级真题解析:动态规划解决小杨买饮料问题(洛谷3873)

一、题目解读小杨买饮料是GESP 2023年六级认证考试中的一道经典动态规划题目,考察学生对背包问题的理解和应用能力。题目描述小杨需要购买n种饮料,每种饮料有特定的体积w和价格v,他要在不超过容量l的...

2024年GESP五级武器强化(洛谷B4071)解题代码C++版

2024年GESP五级武器强化(洛谷B4071)解题代码C++版

一、题目解读    2024年GESP(青少年软件编程能力等级考试)五级中的“武器强化”(洛谷平台题目编号B4071)是一道典型的算法优化问题。题目要求通过合理...

手搓顺序表类代码注释与详解:从零实现动态数组(新手教程)

一、简介和特点顺序表(Sequential List)是数据结构中基础的一种线性表,其特点是将数据元素存储在连续的内存空间中。通过数组实现,支持随机访问(即通过索引直接访问元素),适用于频繁随机读取的...

2024蓝桥杯省赛B组“传送阵”题解(C++代码+图论算法优化)

2024蓝桥杯省赛B组“传送阵”题解(C++代码+图论算法优化)

一、题目解读2024年蓝桥杯省B组“传送阵”题目要求处理一个包含n个节点的图,节点间存在单向传输关系。每个节点i可传送至a[i]指定的节点,形成可能存在的环结构。题目需求解从任意节点出发能到达的最长路...

CSP-J 2019公交换乘题解析:基于队列优化的动态规划代码详解

CSP-J 2019公交换乘题解析:基于队列优化的动态规划代码详解

一、题目解读CSP-J 2019年的“公交换乘”题目(洛谷P5661)要求模拟地铁与公交交替出行的费用计算。题目核心在于地铁消费会产生优惠券,而公交可在45分钟内使用优惠券抵扣车费。需要处理n条出行记...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。