zoukankan      html  css  js  c++  java
  • 区间dp专题

     HDU4283You Are the One区间dp,

    记忆话搜索运行时间:

     
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int maxn = 105,inf = 1<<30;
    int dp[maxn][maxn][maxn],arr[maxn],n;
    int solve(int s,int e,int k){
        if( s == e)return arr[s] * (k-1);
        if( s > e)return 0;
        if(dp[s][e][k] != inf)return dp[s][e][k];
    
        for(int i = s; i <= e; i++){    //将区间[s,e]划分为[s,i],[i+1,e]
            int nextk = k+(i-s)+1;      //[i+1,e]区间内第i个人第nextk个出栈
            int thisk = k+(i-s);        //[s,i]区间的第s个人第thisk个出栈
            int first = solve(s+1,i,k); //第1个区间经过分配得到最少屌丝值
            int second = solve(i+1,e,nextk); //第2个区间经过分配得到的最少屌丝值
            int cur = arr[s] * (thisk-1);     //第s个人第thisk出栈增加的屌丝值
            dp[s][e][k] = min(dp[s][e][k],cur+second+first);
        }
        return dp[s][e][k];
    }
    int main(){
        int t,cas = 1;
        scanf("%d",&t);
        while( t-- ){
            scanf("%d",&n);
            for(int i = 1; i <= n; i++)
                scanf("%d",arr+i);
            for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
            for(int k = 0; k <= n; k++)
            dp[i][j][k] = inf;
            printf("Case #%d: %d
    ",cas++,solve(1,n,1));
    
        }
        return 0;
    }
    
    三个for循环
     
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int maxn =105;
    const int inf = 1<<30;
    int dp[maxn][maxn],arr[maxn],sum[maxn];
    int n;
    int solve_dp(){
        for(int len = 1; len < n; len++){           //枚举区间长度
            for(int s = 1; s + len <= n; s ++){     //枚举区间起点
                int end = s+len;                    //s为区间头,end为区间尾
                for(int k = s; k <= end; k++){      //第k个出栈
                    int tp = arr[s] * (k-s);
                    tp += dp[s+1][k] + dp[k+1][end];
                    tp += (k-s+1) * (sum[end] - sum[k]);//重要的性质,如果第i个人第k个出栈,那么后面的人出栈顺序都大于k
                    dp[s][end] = min(dp[s][end],tp);
                }
            }
        }
        return dp[1][n];
    }
    int main(){
        int t,cas = 1;
        scanf("%d",&t);
        while( t-- ){
            scanf("%d",&n);
            for(int i = 1; i <= n; i++){
                scanf("%d",arr+i);
                sum[i] = sum[i-1] + arr[i];
            }
            memset(dp,0,sizeof(dp));
            for(int i = 1; i <= n; i++)
            for(int j = i+1; j <= n; j++)
            dp[i][j] = inf;
            printf("Case #%d: %d
    ",cas++,solve_dp());
        }
        return 0;
    }
    

     3、poj 2955 Brackets

         经典的区间DP模型--最大括号匹配数。如果找到一对匹配的括号[xxx]oooo,就把区间分成两部分,一部分是xxx,一部分是ooo,然后以此递归直到区间长度为1或者为2.

         状态转移方程:if(mach(j,j+i))dp[j][j+i] = dp[j+1][j+i-1]+2;
                                dp[j][j+i] = max(dp[j][k],dp[k+1][j+i])(j <= k < j+i)

    /*
    ** 一种自底向上型的DP
    ** 状态转移方程:if(mach(j,j+i))dp[j][j+i] = dp[j+1][j+i-1]+2;
    **                dp[j][j+i] = max(dp[j][k],dp[k+1][j+i])(j <= k < j+i)
    */
    #include <stdio.h>
    #include <cstring>
    #define Max(a,b) (a)>(b)?(a):(b)
    #define maxn 101
    int dp[maxn][maxn];
    char str[maxn];
    int main()
    {
         while(~scanf("%s",str)) {
           if(strcmp(str,"end") == 0)break;
              int len = strlen(str);
              memset(dp,0,sizeof(dp));
              for(int i = 1; i <= len; i++) {//枚举区间长度
                   for(int j = 0; j <= len - i; j++) {//枚举起点
                        dp[j][j+i] = dp[j+1][j+i-1] ;
                        if((str[j] == '(' && ')'== str[j+i]) || (str[j] =='[' && str[j+i] == ']' ))
                             dp[j][j+i] += 2;
                        for(int k = j; k < i+j; k++)//枚举区间j->j+i的分界点
                             dp[j][j+i] = Max(dp[j][j+i],dp[j][k]+dp[k+1][j+i]);
                   }
              }
              printf("%d
    ",dp[0][len-1]);
         }
         return 0;
    }
    

     Light OJ 1422 Halloween Costumes

     很基础的区间DP,是不老传说那题的减弱版。

       状态转移方程:

         dp[s][e] = dp[s][e-1] (arr[s] == arr[e]).dp[s][e] = dp[s][e-1]+1 (arr[s] != arr[e]) ;
         dp[s][e] = min(dp[s][e] ,dp[s][k]+dp[k+1][e]);(arr[s] == arr[k] && s <= k < e )
         dp[s][e] = min(dp[s][e] ,dp[s][k]+dp[k+1][e]+1);(arr[s] != arr[k] && s <= k < e)

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int maxn = 110;
    int dp[maxn][maxn],arr[maxn];
    int main()
    {
         int t,cas = 1,n;
         scanf("%d",&t);
         while( t-- ) {
              scanf("%d",&n);
              for(int i = 1; i <= n; i++)
                   scanf("%d",&arr[i]);
              memset(dp,0,sizeof(dp));
              for(int i = 1; i <= n; i++)dp[i][i] = 1;
              for(int i = 1; i <= n; i++)
                   for(int j = 1; j <= n-i; j++) {
                        dp[j][j+i] = dp[j][j+i-1];
                        if(arr[j] != arr[j+i])dp[j][j+i]++;//当起点和终点不同时衣服数量加1
                        for(int k = j; k < j+i; k++) {
                             if(arr[j] == arr[k])
                                  dp[j][j+i] = min(dp[j][j+i],dp[j][k]+dp[k+1][j+i]);//当第j和第k相等时,衣服数量等于(j->k) + (k+1->j+i)
                             else
                                  dp[j][j+i] = min(dp[j][j+i],dp[j][k]+dp[k+1][j+i]+1);//当j和k不相等时,衣服数量等于(j->k) + (k+1->j+i)  + 1
                        }
                   }
              printf("Case %d: %d
    ",cas++,dp[1][n]);
         }
         return 0;
    }
    
  • 相关阅读:
    清北学堂(2019 5 3) part 6
    清北学堂(2019 5 2) part 5
    清北学堂(2019 5 1) part 4
    dijkstra
    清北学堂(2019 4 30 ) part 3
    2020/5/1
    2020/4/30
    2020/4/29
    HSV模型
    2020/4/28
  • 原文地址:https://www.cnblogs.com/LUO257316/p/3252322.html
Copyright © 2011-2022 走看看