zoukankan      html  css  js  c++  java
  • UVA 10559 Blocks(区间DP&&递推)

    题目大意:给你玩一个一维版的消灭星星,得分是当前消去的区间的长度的平方,求最大得分。

    现在分析一下题目

    因为得分是长度的平方,不能直接累加,所以在计算得分时需要考虑前一个状态所消去的长度,仅用dp[l][r]来表示区间最大得分是不足以用来转移的。

    我们的解决方法是:增加一维预测未来可能会出现的情况,用dp[l][r][t]表示区间[l,r]之后附加t个与r同色的方块时所能得到的最大值。为了降低时间复杂度,我们可以在读入时处理一下,将一段长度为a、颜色为b的区间k表示成一个len[k]=a,col[k]=b的“点”。这样,当我们计算dp[l][r][0]时,首先尝试直接消除区间r,得到dp[l][r][0]=dp[l][r-1][0]+(len[r])^2,接着,将它之后所有可能的附加t个同色方块的情况都算出来:dp[l][r][t]=dp[l][r-1][0]+(len[r]+t)^2。之后,在[l,r-1]之间寻找可能与区间r同色的区间k,若col[r]==col[k],则尝试消除区间r与k之间的所有方块,让区间r与k并在一起计算分数并更新所有dp[l][r][t]的值:dp[l][r][t]=max(dp[l][r][t],dp[l][k][len[r]+t]+dp[k+1][r-1][0])。最后dp[1][n][0]即为答案。(n为一开始同色区间的数量)

    代码:(140ms,用递推速度就是不一样,比记搜不知道高到哪里去了)

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    int col[210],len[210],dp[210][210][210];
    int sum[210];
    //by sclbgw7
    inline int sq(int x)
    {return x*x;}
    
    inline int maxn(int x,int y)
    {return x>y?x:y;}
    
    int main()
    {
        int T,time;
        scanf("%d",&T);
        for(time=1;time<=T;++time)
        {
            int n=0,m,t1;//m为方块个数,n为区间个数
            scanf("%d",&m);
            for(int i=1;i<=m;++i)
            {
                scanf("%d",&t1);
                if(t1==col[n])
                  ++len[n];
                else
                {
                    col[++n]=t1;
                    len[n]=1;
                }
            }
            for(int i=1;i<=n;++i)
              sum[i]=sum[i-1]+len[i];//sum为前缀和,用于限定预测t的范围
            memset(dp,0,sizeof(dp));
            for(int i=0;i<n;++i)
              for(int l=1;l+i<=n;++l)
                {
                    int r=l+i,re=sum[n]-sum[r];//re为当前t可能用到的最大值
                    for(int t=0;t<=re;++t)
                      dp[l][r][t]=dp[l][r-1][0]+sq(t+len[r]);
                    for(int k=r-1;k>=l;--k)
                      if(col[k]==col[r])
                        for(int t=0;t<=re;++t)
                          dp[l][r][t]=maxn(dp[l][r][t],dp[l][k][len[r]+t]+dp[k+1][r-1][0]);
                }
            printf("Case %d: %d\n",time,dp[1][n][0]);
            //神坑!!!!!冒号之后要加一个空格!!!!!!!
        }
        return 0;
    }
  • 相关阅读:
    做才是得到
    常用工具汇总
    迎接2017
    新年礼物
    2017
    asp.net core 日志
    板子|无向图的割点
    11/06信竞快乐模拟赛
    动态规划复习
    894D
  • 原文地址:https://www.cnblogs.com/sclbgw7/p/8244953.html
Copyright © 2011-2022 走看看