zoukankan      html  css  js  c++  java
  • [洛谷1437&Codevs1257]敲砖块<恶心的dp>

    题目链接:https://www.luogu.org/problem/show?pid=1437#sub

         http://codevs.cn/problem/1257/

    不得不说,这个题非常的恶心,在初次拿到题后我的思路是暴力,思索之后我还是只有暴力,想到最后我还是暴力,当然暴力的方法就是智者见智的了;

    在看了题解的思路后,我尝试着去打着到题,结果,完美WA掉。。。然后我就WA了接近一周时间,最后浏览了各种博客才勉强A了这道恶心的dp

    很多大佬的博客对于这道题的解法都是要转90度然后才定义dp,说实话,我觉得那种方法略偏麻烦,完全可以不处理原图直接dp

    对于这道题,第一件事就是要怎么去看这张图

    14   15   4   3   23

        33   33   76   2

        2   13   11

          22   23

            31

    这是题干里的图,当然在看这张图的时候,要稍微换个方式

    14  15  4    3  23

    33  33  76  2

    2    13  11

    22  23

    31

    这张图有没有很熟悉,想起了啥???我反正是想起了dp入门题里面一道类似的三角形的题,不过图倒过来了

    当然就算想起来了也没有大用处,因为这不是重点。

    把图变成这样主要是为了方便分析滴

    我们来定义一个数组吧:(这才是重点)

    定义数组dp[i][j][k]表示第i列第j块砖时已经一共取了k块砖  (也可以理解为,第i列取了j块砖且一共去了k块砖)

    好了定义出来了我相信这个方程其实也很容易搞出来了,要注意的是我们要从第n列往回找,不要问我为啥,因为不这样找,你的dp数组就会有些地方没有值

    动态转移方程

    ----------------------------------------------------------------------------------------------------------------------------------

    --                                                    --

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

    --                                                    -- 

    ----------------------------------------------------------------------------------------------------------------------------------

    然后我就来解释一下这个动态转移方程

    *dp[i+1][v][k-j]中,v是从j-1到m,因为在第i列取了j个砖头,所以第i+1列至少要去j-1个(通过题中条件,取第i,j块必须先取i-1, j+1和i-1,j)

     然后在第i列是一共取k个,所以第i+1列肯定是一共取了k-j个

    *sum[j][i]是表示从a[1][i]到a[j][i]的值的和。因为你取第i列第j块,肯定是在第i列上要把前j个取完的

    把这些个一想通,这题就明了了,一个预处理sum[][],在来个4重循环跑个dp数组就完了

    唯一还值得注意就是ans是可能存在dp数组的任何位置,所以一边动态转移,一边要比较ans

    题不难,就看细心了

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<iostream>
     5 #include<cstdlib>
     6 #include<cmath>
     7 #define maxn 55
     8 #define maxm 1300
     9 using namespace std;
    10 
    11 int n,m,ans;                    
    12 int f[maxn][maxn][maxm];            
    13 int val[maxn][maxn];            
    14 
    15 int main()
    16 {
    17     scanf("%d%d",&n,&m);
    18     memset(f,-1,sizeof(f));
    19     for(int i=1;i<=n;i++)
    20     {
    21         for(int j=1;j<=n-i+1;j++)
    22         {
    23             scanf("%d",&val[i][j]);
    24             val[i][j]+=val[i-1][j];
    25         }
    26     }
    27     f[n][1][1]=val[1][n];
    28     for(int i=n-1;i>=1;i--)
    29      for(int j=0;j<=n-i+1;j++)
    30       for(int k=j;k<=min(m,(n-i+1)*(n-i+2)/2);k++)
    31       //第i列的时候,最多取了p*(p+1)/2块砖头 p=n-i+1
    32       {
    33           for(int v=max(j-1,0);v<=n-i;v++)//i+1列最多就n-i块砖 
    34           {
    35             if(f[i+1][v][k-j]!=-1&&f[i+1][v][k-j]+val[j][i]>f[i][j][k])
    36                 f[i][j][k]=f[i+1][v][k-j]+val[j][i];         
    37           }
    38           ans=max(ans,f[i][j][k]);
    39       }
    40     printf("%d",ans);
    41 }
    View Code
  • 相关阅读:
    图论————拓扑排序
    状态压缩DP:蒙德里安的梦想
    差分+贪心:IncDec序列
    三目运算符
    贪心+高精度:国王游戏
    图论——最小生成树:Prim算法及优化、Kruskal算法,及时间复杂度比较
    图论——Floyd算法拓展及其动规本质
    图论——最短路:Floyd,Dijkstra,Bellman-Ford,SPFA算法及最小环问题
    贪心+DFS:引水入城
    网站移动版本开发踩坑实录一
  • 原文地址:https://www.cnblogs.com/Danzel-Aria233/p/7528455.html
Copyright © 2011-2022 走看看