• 区间DP


    算法思想

    • 概念:区间类动态规划是线性动态规划的扩展,它在分阶段地划分问题时,与阶段中元素出现的顺序和由前一阶段的哪些元素合并而来由很大的关系。令状态dp[i][j]表示将下标位置i到j的所有元素合并能获得的价值的最大值.
    • 状态转移方程: (dp[i][j] = max{dp[i][k] + dp[k+1][j] + cost}),cost为将这两组元素合并起来的代价。
    • 特征 :能将问题分解为能两两合并的形式
    • 步骤:由于计算dp[i][j]的值时需要知道所有dp[i][k]和dp[k+1][j]的值,而这两个中包含的元素的数量都小于dp[i][j],所以我们以 len = j-i+1作为DP的阶段。首先从小到大枚举len,然后枚举i的值,根据len和i用公式计算出j的值,然后枚举中间点k,时间复杂度为O(n^3)
    • 核心代码
        MS(dp , 0);//清零
        for(int len=2; len<=n; len++){ //枚举长度
            for(int i=0; i<n; i++){//枚举起点
                int j = i + len - 1;//计算终点
                if(j >= n) break;//不可越界
                if(conditon) state transition...//根据条件写状态转移方程
                for(int k=i; k<j; k++){ //枚举中间点,合并
                    dp[i][j] = max(dp[i][j] , dp[i][k] + dp[k+1][j] + cost)
                }
            }
        }
    

    入门例题

    • 括号最大匹配
    int dp[maxn][maxn];
    string s;
    int n;
    void solve(){
        rep(len , 2 , n){
            rep(i , 0, n - 1){
                int j=i+len-1;
                if(j >= n) break;
                //cout<<s[i]<<": "<<s[j]<<endl;
                if(s[i] == '(' &&  s[j] == ')' ||  s[i] == '[' &&  s[j] == ']') dp[i][j] = dp[i+1][j-1] + 2;
                rep(k, i, j-1){
                    dp[i][j] = max(dp[i][j] , dp[i][k] + dp[k+1][j]);
                }
            }
        }
    }
    
    int main(){
        while(cin>>s){
           
            if(s == "end") break;
            n = s.length();
            MS(dp , 0);
            solve();
            cout<<dp[0][n-1]<<endl;
        }
        return 0;
    }
    
    
    
    • Multiplication Puzzle POJ - 1651
      • 一个序列,头尾不取,每次取掉一个数得分a[i]a[i-1]a[i+1],如何取中间的数字使得最后的得分最少
      • 假设有一个区间[l,r],dp[i][j]表示i,j位置不取,最终可以得到的最小值,对于区间[l,r],最后一步必然是a[l],a[k],a[r]并且取走a[k],k是中间点且不是端点
      • 假设dp[l,k] dp[k][r]已经算出来了,枚举K的位置,状态转移方程(dp[i][j] = min(dp[i][j] , dp[i][k] + dp[k][j] + a[i]*a[k]*a[j]);)
    ll a[maxn];
    ll dp[maxn][maxn];
    
    
    void solve(){
        rep(len , 3 , n){ //枚举区间长度,长度至少是3
            rep(i, 1, n){ //枚举起点
                int j=i+len-1; //得到终点
                if(j > n) break; //检查越界
                dp[i][j] = inf; //求最小值 先初始化inf
                rep(k, i+1, j-1){ //枚举中间点
                    dp[i][j] = min(dp[i][j] , dp[i][k] +  dp[k][j] + a[i]*a[k]*a[j]);
                }
            }
        }
    }
    
    
    int main(){
        while(sc(n) != EOF){
            rep(i,1,n) scl(a[i]); //从1开始读数字
            MS(dp,0);//初始化DP
            solve();
            cout<<dp[1][n]<<endl;
        }
        return 0;
    }
    
    
  • 相关阅读:
    Device eth0 does not seem to be present, delaying initialization(解决克隆CentOS6.3虚拟机后网卡设备无法启动问题)
    CI整合Smarty
    修改crontab默认的编辑器
    添加数据之后不跳页面显示一个漂亮的提示信息(非ajax提交数据)
    jsp连接mysql数据库
    PHP使用CURL详解
    内、外部号码范围配置
    更改SAP的字段翻译
    SAP 应用服务负载均衡的实现
    SAP中禁止特定用户更改密码
  • 原文地址:https://www.cnblogs.com/czsharecode/p/12308148.html
Copyright © 2020-2023  润新知