• 最基础的区间DP 小结


    最基本的思想依旧是分治,对于每段区间都由更小的区间最优值组合得到。

    Step://模板 //区间最优解

    变量:

             dp[i][j]:区间[i,j]的最优解(dp[i][i]对角线视情况而定);

             k:每次将区间[i,j]分为更小的区间组合[i,k]+[k,j];

    三层循环:

             最外层:for(int l=1;l<=len;l++) //区间长度枚举

             第二层:for(int i=1;i<=len-l+1;i++)  //起点+终点枚举

                         int j=i+l-1; dp[i][j]=***;

              内层: for(int k=i;k<j;k++)  //枚举区间内部分割点k

                          dp[i][j]=max/min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sun[i-1]);

    Step://模板 //区间计数 //另一种写法??  //还是要灵活一点,这些是最最简单基础的板子

    变量:

             dp[i][j]:区间[i,j]的最优解(dp[i][i]对角线视情况而定);

             k:每次将区间[i,j]分为更小的区间组合[i,k]+[k,j];

             记得初始化dp;

    三层循环:

             最外层:for(int i=1;i<=n;i++)  //枚举起点

             第二层:for(int j=i+1;j<=n;j++ //终点枚举

                         //有时需要处理dp[i][j]

              内层: for(int k=i;k<=j;k++)  //枚举区间内部分割点k

                          dp[][]递推式

    简单的基础题(中文题……不解释):

    1.石子归并

    51 nod 1021  传送门

    #include<iostream>
    #include<algorithm>
    #include<string.h>
    #include<stdio.h>
    using namespace std;
    int n, sum[105],a;
    int dp[105][105];
    int main()
    {
        while (cin>>n)
        {
            sum[0] = 0;
            for (int i = 1; i <= n; i++)
            {
                scanf("%d", &a);
                sum[i] = sum[i - 1] + a;
            }
            memset(dp, 0, sizeof(dp));
            for(int l=2;l<=n;l++)
                for (int i = 1; i <= n - 1 + 1; i++)
                {
                    int j = i + l - 1;
                    dp[i][j] = 0x3f3f3f3f;
                    for (int k = i; k < j; k++)
                    {
                        dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + sum[j] - sum[i - 1]);
                    }
                }
            printf("%d
    ", dp[1][n]);
        }
        return 0;
    }

    POJ 2955 括号匹配

    求括号匹配的最大值

    #include<iostream>
    #include<algorithm>
    #include<string.h>
    #include<stdio.h>
    #include<string>
    using namespace std;
    typedef long long ll;
    int n;
    int dp[110][110];
    string s;
    int main()
    {
        while (cin>>s)
        {
            int len = s.length();
            memset(dp, 0, sizeof(dp));
            for(int l=2;l<=len;l++)
                for (int i = 0; i <= len - l+1 ; i++)
                {
                    int j = i + l-1 ;
                    if ((s[i] =='('&& s[j]==')')||(s[i]=='['&&s[j]==']'))
                        dp[i][j] = dp[i + 1][j - 1] + 2;
                    else dp[i][j] = dp[i + 1][j - 1];
                    for (int k = i; k < j; k++)
                    {
                        dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j]);
                    }
                }
            cout << dp[0][len - 1] << endl;
        }
        return 0;
    }

    Light oj 1422

    改了好久啊……这个……

    emmmmmmm跟前面的题还是稍微有些不太一样,这里需要逆向推(正向推的话,需要考虑的情况有很多,当前衣服跟前面的衣服有没有一样的啊,是脱了还是还在里面套着啥的……总之就是很乱很杂的感觉??但是,如果逆向考虑的话,只需要看当前衣服是不是只在此时使用),下面来看一看递推的式子↓

    很容易想到,如果最i处的衣服只在i处使用,那么dp[i][j]=dp[i+1][j]+1;

                        如果i处衣服在j处也使用的话(a[i]==a[j]),那么dp[i][j]=min(dp[i][j],dp[i+1][k-1]+dp[k][j]);

    ps:不要忘记初始化dp

    #include<iostream>
    #include<algorithm>
    #include<string.h>
    #include<stdio.h>
    #include<string>
    using namespace std;
    typedef long long ll;
    int n,a[110],t;
    int dp[110][110];
    int main()
    {
        cin >> t;
        int cnt = 0;
        while (t--)
        {
            cin >> n;
            memset(dp, 0, sizeof(dp));
            for (int i = 1; i <= n; i++)
            {
                cin >> a[i];
                dp[i][i] = 1;
            }
                for (int i = n-1; i >0; i--)
                {
                    for (int j = i + 1; j <= n; j++)
                    {
                        dp[i][j] = dp[i + 1][j] + 1;
                        for (int k = i; k <=j; k++)
                        {
                            if (a[i] == a[k])
                                dp[i][j] = min(dp[i][j], dp[i+1][k-1] + dp[k][j]);
                        }
                    }
                }
            cout << "Case "<<++cnt<<": " << dp[1][n] << endl;;
        }
        return 0;
    }

    NYOJ 746  整数划分

    emmmm……都写到注释里了,,,(自己还是写不出来,,,还是要看别人的题解orz,不要方!人一我百,人十我万!早晚会写出来的)

    #include<iostream>
    #include<algorithm>
    #include<string.h>
    #include<stdio.h>
    #include<string>
    using namespace std;
    typedef long long ll;
    int n,t,m;
    ll a[25][25];
    ll dp[25][25];//表示到i为止,填j个乘号的最大值
    string s;
    int main()
    {
        cin >> t;
        while (t--)
        {
            cin >> s>>m;
            m--; //拆分为m组数的乘积,添加m-1个*
            n = s.length();
            for (int i = 0; i < n; i++)  //字符串转换为数
            {
                a[i][i] = s[i] - '0';
                for (int j = i + 1; j < n; j++)
                    a[i][j] = a[i][j - 1] * 10 + s[j] - '0';
            }
            memset(dp, 0, sizeof(dp));
            for (int i = 0; i < n; i++) //初始化dp,dp[i][0]→不添*→a[0][i]
                dp[i][0] = a[0][i];
            for (int j = 1; j <= m; j++) //枚举添*的个数
                for (int i = j; i < n; i++)  //添加j个*至少有i+1个数,i+1个数有i个间隔,所以初始条件为i=j(此处s下标是从0开始的)
                    for (int k = 0; k < i; k++)//枚举*添加的位置
                        dp[i][j] = max(dp[i][j], dp[k][j - 1] * a[k+1][i]); //最优解为此时dp[i][j]和添加j-1个*时的dp[k][j-1]与末尾数值的乘积
            cout << dp[n-1][m] << endl;
        }
        return 0;
    }

     hdu 4238 You are the one

    dp[i][j]:i~j的最优解(不考虑i之前和j之后的人,只考虑[i,j])

    递推公式:dp[i][j]=min(dp[i][j],dp[i+1][k]+dp[k+1][j]+d[i]*(k-i)+(sum[j]-sum[k])*(k-i+1));

                      把黑屋子看成栈,对于每个区间[i,j],考虑将i扔到黑屋子里去~然后枚举出栈的位置~

                       i处进栈k处出栈,上台顺序就变为i+1,i+2......i,k+1,k+2.....j最优为min(dp[i+1][k]+dp[k+1][j]+d[i]*(k-i)+(sum[j]-sum[k])*(k-i+1));

                       //只考虑[i,j],看成把i~j单独拿出来的子列                                                                                ↑i前面有(k-i)个人  ↑k+1~j前面有(k-i+1)个人

    #include<iostream>
    #include<string>
    #include<algorithm>
    using namespace std;
    int t,dp[105][105],d[105],n;
    int sum[105];
    int main()
    {
        cin >> t;
        for (int m = 1; m <= t; m++)
        {
            memset(dp, 0, sizeof(dp));
            cin >> n;
            sum[0] = 0;
            for (int i = 1; i <= n; i++)
            {
                cin >> d[i];
                sum[i] = sum[i - 1] + d[i];
            }
            for(int l=1;l<n;l++)
                for (int i = 1; i <= n - l; i++)
                {
                    int j = i + l;
                    if(i<j)
                    dp[i][j] = 0x3f3f3f3f;
                    for (int k = i; k <= j; k++)
                    {
                        dp[i][j] = min(dp[i][j], dp[i+1][k] + dp[k + 1][j] + d[i] * (k - i) + (sum[j] - sum[k])*(k - i+1));
                    }
                }
            cout <<"Case #"<<m<<": "<< dp[1][n] << endl;
        }
        return 0;
    }

     hdu 2476

    #include<iostream>
    #include<string>
    #include<algorithm>
    using namespace std;
    int dp[105][105];
    int ans[105];
    string s, t;
    int main()
    {
        while (cin >> s)
        {
            cin >> t;
            int len = t.length();
            memset(dp, 0, sizeof(dp));
            for(int j=0;j<len;j++)
            {
                for(int i=j;i>=0;i--)
                {
                    dp[i][j] = dp[i + 1][j] + 1;
                    for (int k = i+1; k <= j; k++)
                        if(t[i]==t[k])
                        dp[i][j] = min(dp[i][j], dp[i+1][k] + dp[k + 1][j]);
                }
            }
            for(int i=0;i<len;i++)
                ans[i] = dp[0][i];
            for (int i = 0; i < len; i++)
            {
                if (s[i] == t[i])
                    ans[i] = ans[i - 1];
                else
                {
                    for (int j = 0; j < i; j++)
                        ans[i] = min(ans[i], ans[j] + dp[j + 1][i]);
                }
            }
            cout << ans[len - 1] << endl;
        }
        return 0;
    }
  • 相关阅读:
    Java Spring AOP用法
    Spring IOC的简单实现
    随机数
    Java 正则表达式
    日期格式转换
    maven settings.xml详解
    JSP与Servlet的关系
    EL表达式学习
    FreeMarker学习2
    FreeMarker学习
  • 原文地址:https://www.cnblogs.com/Egoist-/p/7704620.html
Copyright © 2020-2023  润新知