zoukankan      html  css  js  c++  java
  • HDU2476 String painter (区间dp+思维详细题解)

    对于这道题,我发现好多网上的题解对dp的物理意义讲的并不是十分透彻,但是代码又是正确的,这样初学者会感到十分难以接收dp的正确性

    在这篇题解,我会讲解我的dp方程的物理意义(其实是对网上代码的理解之后的自己的想法),这题我觉得思维难度还是挺大的,如果是第一次做的话

    首先我们看到什么改变字符串,又是最小,很容易想到dp,并且是区间dp

    所以我们自然而然地会想到f[l][r],表示将a转移成b的最小代价,其实这样也能做,但是我们下次遇到这种题目的话,可以先转换成空串转移到b串,之后再与a串进行对比

    下面我们来讲解代码中的难点

    1.首先我们要相信这个状态定义的正确性,如果我们在l-r范围是最小的,那么显然在大区间中使用这个答案是没有问题的,不可能说我整个大区间的最小值不是由小区间转移过来的

    因为区间dp是按照长度来一层层递增的,我们在更新每个大1区间的时候,都是根据小区间的最小值转移过来,这样这个大区间就是最小的,同理可以一直递推上去。

    2.为了更好理解,我们可以先对长度为1的区间进行初始化,所有f[i][i]=1,这是很合理的。

    3.核心代码讲解

    for(len=2;len<=n;len++){
                for(l=1;l+len-1<=n;l++){
                    r=l+len-1;
                    f[l][r]=f[l][r-1]+1;
                    for(k=l;k<r;k++){
                        if(b[k]==b[r]){
                            f[l][r]=min(f[l][r],f[l][k-1]+f[k][r-1]);
                        }
                    }
                }
            }

    首先f[l[][r]=f[l][r-1]+1,因为我们最坏的情况就是直接对这个点进行改变成和b相等的情况

    之后我们枚举每个断点,这也是区间dp的常见手法,这里的意义就是如果我们在这段区间内有一个点b[k]的值和b[r]的值是相同的,那么就有可能可以优化

    因为k和r相等,那么我们在涂k的时候,完全可以先把k-j都涂成相同的值,这样我们涂k-r就相当于涂k--r-1,因为我们肯定要涂k,在这个时候顺便把k-r涂成同一个值,所以涂r就可以不用额外算

    这样改变的最小值就成为f[l][k-1](前k-1的最小值)+f[k][r-1];

    4.之后我们再考虑a串的情况

    最坏的情况就是跟空串一样,所以先赋初值。

    显然如果a[i]==b[i],ans[i]=ans[i-1],ans[i]代表的是从1-i的最小代价

    这样的话就可以直接continue了,不用进行下面的循环,我在网上看到他们没有continue,让我一度无法理解下面的ans的转移方程的正确性,我当时一直在想为什么相等了还会有更小的情况

    实际如果相等,就不用进行下面的for循环了。

    那么下面的for循环的物理意义就是,也相当于如果两个位置不相等,我们不知道从之前哪个位置涂到这个位置才会使前i个最小,所以进行暴力枚举。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    using namespace std;
    const int N=1e5+10;
    const int inf=0x3f3f3f3f;
    int    f[102][102];
    int ans[N];
    int main(){
        int i;
        string s,b;
        while(cin>>s>>b){
            memset(f,0x3f,sizeof f);
            memset(ans,0,sizeof ans);
            s=" "+s;
            b=" "+b;
            int j;
            int n=s.size();
            for(i=1;i<=n;i++){
                f[i][i-1]=0;
            }
            
            for(i=1;i<=n;i++){
                f[i][i]=1;
            }
            int len,l,r;
            int k;
            for(len=2;len<=n;len++){
                for(l=1;l+len-1<=n;l++){
                    r=l+len-1;
                    f[l][r]=f[l][r-1]+1;
                    for(k=l;k<r;k++){
                        if(b[k]==b[r]){
                            f[l][r]=min(f[l][r],f[l][k-1]+f[k][r-1]);
                        }
                    }
                }
            }
            for(i=1;i<=n;i++){
                ans[i]=f[1][i];
                if(s[i]==b[i]){
                    ans[i]=ans[i-1];
                    continue;
                }
                for(int j=1;j<=i;j++)
                ans[i]=min(ans[i],ans[j-1]+f[j][i]);
            }
            cout<<ans[n]<<endl;
        }
        return 0;
    }
    View Code
  • 相关阅读:
    mysq 日期相减
    说说时间观与时间管理——北漂18年(71)
    ionic之切换开关
    ionic之单选框
    SELECT ... LOCK IN SHARE MODE和SELECT ... FOR UPDATE locks在RR模式下可以看到最新的记录
    14.5.2.3 Consistent Nonlocking Reads 一致性非锁定读
    14.5.2.2 autocommit, Commit, and Rollback
    14.5.2 事务隔离级别
    对于唯一索引使用唯一条件搜索, InnoDB 只锁定找到的index record,不是它之前的区间
    mysql explain 解释
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/12328992.html
Copyright © 2011-2022 走看看