• 区间DP总结


    做了一些区间DP的题目,总结如下

    1.Multiplication Puzzle

    原题地址:http://poj.org/problem?id=1651

    题意:

    给定一个序列,可以依次从序列中取走除了左右两端点之外的元素,每次取走一个元素,获得该元素乘以它左右两边元素乘积的点数,求可能的最小点数

    题解:

    枚举区间中最后一个被取走的元素,实现区间的分割,也就是状态的转移。

    详细的解题报告

    2.Dire Wolf

    原题地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=5115

    题意:

    有一群狼站成一排,每个狼有基础的攻击力,同时有一个辅助攻击力,每个狼的总攻击力是基础攻击力加上相邻的狼给予的辅助攻击力之和,求杀狼的次序使得收到的总攻击力之和最小。

    题解:和上一题非常相似

    #include<bits/stdc++.h>
    
    #define clr(x,y) memset((x),(y),sizeof(x))
    
    using namespace std;
    typedef long long LL;
    
    const int maxn=200;
    const int inf=1e9;
    
    int A[maxn+5];
    int B[maxn+5];
    int dp[maxn+5][maxn+5];
    int n;
    
    int DP(int l,int r)
    {
        if (dp[l][r]!=-1) return dp[l][r];
        if (l==r-1) return dp[l][r]=0;
    
        dp[l][r]=inf;
        for (int k=l+1;k<=r-1;++k)
        {
            int tmp=A[k]+B[l]+B[r];
            dp[l][r]=min(dp[l][r],DP(l,k)+DP(k,r)+tmp);
        }
        return dp[l][r];
    }
    void solve(int C)
    {
        A[0]=0;
        A[n+1]=0;
        B[0]=0;
        B[n+1]=0;
    
        clr(dp,-1);
        int ans=DP(0,n+1);
    
        printf("Case #%d: %d
    ",C,ans);
    }
    
    int main(void)
    {
        #ifdef ex
        freopen ("../in.txt","r",stdin);
        //freopen ("../out.txt","w",stdout);
        #endif
    
        int T;
        scanf("%d",&T);
    
        for (int Case=1;Case<=T;++Case)
        {
            scanf("%d",&n);
            for (int i=1;i<=n;++i) scanf("%d",&A[i]);
            for (int i=1;i<=n;++i) scanf("%d",&B[i]);
    
            solve(Case);
        }
    }
    View Code

    3.男神的礼物

    原题地址:http://acm.uestc.edu.cn/#/problem/show/1131

    题意:略

    题解:略

    #include<bits/stdc++.h>
    
    #define clr(x,y) memset((x),(y),sizeof(x))
    
    using namespace std;
    typedef long long LL;
    
    const int maxn=100;
    const int inf=1e6;
    
    int n;
    int dp[maxn+5][maxn+5];
    int A[maxn+5];
    int sum[maxn+5];
    
    void solve()
    {
        clr(dp,0);
        clr(sum,0);
        for (int i=1;i<=n;++i)
            sum[i]=(sum[i-1]+A[i])%100;
    
        for (int i=n;i>=1;--i)
        {
            for (int j=i;j<=n;++j)
            {
                dp[i][j]=inf;
                if (i==j) dp[i][j]=0;
                for (int k=i;k<=j-1;++k)
                {
                    int c1=(sum[k]-sum[i-1]+100)%100;
                    int c2=(sum[j]-sum[k]+100)%100;
                    dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+c1*c2);
                }
                //printf("%d %d %d
    ",i,j,dp[i][j]);
            }
        }
    
        printf("%d
    ",dp[1][n]);
    }
    
    int main(void)
    {
        #ifdef ex
        freopen ("../in.txt","r",stdin);
        //freopen ("../out.txt","w",stdout);
        #endif
    
        int T;
        scanf("%d",&T);
    
        while (T--)
        {
            scanf("%d",&n);
            for (int i=1;i<=n;++i) scanf("%d",&A[i]);
    
            solve();
        }
    }
    View Code

    (对于区间DP,循环的写法相比记忆化要快若干倍,但是也更容易写错,包括初始化,边界条件等都需要注意)

    4.You Are the One (难)

    原题地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=4283

    题意:略

    题解:通过枚举区间左端点的出栈时间实现了区间的分割

    详细的解题报告

    5.Coloring Brackets

    原题地址:http://www.codeforces.com/contest/149/problem/D

    题意:略

    题解:略

    详细的解题报告

    6.柱爷的恋爱

    原题地址:http://acm.uestc.edu.cn/#/problem/show/1321

    题意:略

    题解:枚举左端点的配对括号来实现区间的分割。

    详细的解题报告

    总结:

    区间DP主要涉及两类问题,区间最优解和区间计数。

    区间最优解往往要枚举区间的分界点,分割区间,子区间的最优解合并之后就是原区间的最优解。

    区间计数往往也要分割区间,但是有不遗漏不重复的要求,以上的两道题都用到了枚举左端点对应元素的技巧。

    区间的分割是区间DP的重要思想

  • 相关阅读:
    Linux定时任务实现每秒执行一次
    go 操作 Excel
    带你十天轻松搞定 Go 微服务系列全集+勘误
    debian修改crontab默认编辑器为vim
    LeetCode 537 复数乘法
    LeetCode 219 存在重复元素 II
    centos8 安装docker
    Linux 文件管理之vim命令详解
    linux 网络管理之nmcli命令详解
    Windows通过计划任务定时执行bat文件
  • 原文地址:https://www.cnblogs.com/123-123/p/5813327.html
Copyright © 2020-2023  润新知