acm周中学习总结

近期总结:
先说说做题。做题依旧困难,仍要不断打磨技巧,多看多打。关键是能够准确辨认dp类型,这需要经验和方法。
动态规划一直是acm竞赛的热点,近来也越来越向思维性强上靠拢。思考清楚问题才是学好的关键。
省赛快到了,不过跟我这个刚刚才接触算法的菜鸟没啥关系,虽然有机会报名但是我没报。我想我还是继续提升自身能力吧。厚积薄发,争取以后的机会。
近期所学:
本周开始了区间dp的学习,下面总结下区间dp的知识点:

区间dp就是在一个区间上寻找最优值类型的dp。每次可以缩小区间范围,寻求最优。核心是把一个大区间分成若干小区间,先求小区间的最优值,合并起来求大区间的最优值。

像经典的石子问题,一开始看起来很像是贪心求解最优解,但是贪心并不能得到最优解。因为阶段和阶段之间是有联系的,贪心只是考虑了极端两个。考虑用dp做就是一种正确的思路。这个dp有固定的思路和方法,类型大体一致,都是考虑区间状态,因而被称为区间dp。

//一般区间DP实现代码
memset(dp, 0x3f, sizeof(dp));
for (int i = 1; i <= n; i++) //区间长度为1的初始化
    dp[i][i] = 0;
for (int len = 2; len <= n; len++) //枚举区间长度
{
    for (int i = 1, j = len; j <= n; i++, j++) //区间[i,j]
    {
        //DP方程实现
    }
}

看一个经典问题:石子合并问题:
题意:有若干堆石子在一条直线上,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
试设计出1个算法,计算出将N堆石子合并成1堆的最小得分。

分析:假设从头到尾是一个大区间,要求最小得分,可以考虑分区间寻找,逐步缩小区间范围。用二维数组dp[i][j]表示从i到j这一区域的石子花费。考虑动态规划必须考虑状态,这个问题中的状态就是一个个小区间,状态和状态之间的转移就是区间的从大到小。
伪代码:

memset(dp, 0x3f, sizeof(dp));
for (int i = 1; i <= n; i++) 
    dp[i][i] = 0;
for (int len = 2; len <= n; len++)
{
    for (int i = 1, j = len; j <= n; i++, j++)
    {
        for (int k = i; k < j; k++)
        {
            if(dp[i][j] > dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1])
                dp[i][j] = dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1];
        }
    }
}printf("%d\n", dp[1][n]);

以上就是我对区间dp的理解
还是继续做题巩固知识,整理思路吧。

你可能感兴趣的:(ACM学习总结)