DP 合集

写这篇博客是为了将这几天写的DP(递推)题的思路总结一下,免得以后忘了,毕竟现在还学得糊里糊涂。。。

A 数塔

题意:给你一个数塔只能从根节点忘左右儿子走,问怎么走到底层使得经过的数之和最大?

思路:

 变量声明:dp[i][j] 以第i层第j个结点为根节点的树能得到的最大和        a[i][j] :存储题目所给的数塔 

 状态转移方程:dp[i][j]=根节点的值+max(左子树,右子树)

核心代码:

for(int j=1;j<=n;j++)
            maxsum[n][j]=a[n][j];
for(int i=n-1;i>0;i--)
    for(int j=1;j<=i;j++)
      maxsum[i][j]=max(maxsum[i+1][j]+a[i][j],a[i][j]+maxsum[i+1][j+1]);

B 一只小蜜蜂

题意:给出蜜蜂的蜂房示意图,并标好了编号,小蜜蜂只能通过六边形蜂房的右边三条边爬向相邻的蜂房,问小蜜蜂从a房到b房的可能路线数?

思路:根据所给图可得出规律 :

           1、 当a与b相差1即b在a的右上或右下方,路线只有一种

           2、当a与b相差2时即b在a的正右方,路线有两种,例如1--3:有1--2--3,1--3两种路线。

           3、其他情况有递推公式: a[i][i+r]=a[i][i+r-1]+a[i][i+r-2],例如到5的路线数 = 到3的路线数+到4的路线数。

核心代码:

for(int r=1;r<=48;r++)
    {
        for(int i=1;i+r<50;i++)
        {

            if(r==1)
                a[i][i+r]=1;
            else if(r==2)
                a[i][i+r]=2;
            else
                a[i][i+r]=a[i][i+r-1]+a[i][i+r-2];
        }
    }

C - 折线分割平面

题意:(中文题目:要求的是n条折线分割平面的最大数目)

思路: 经过观察,你可以发现,如果在相邻的两个线段(或者射线)上任选取两个点,将这两点连线,那么原来的一个区域就会多被分割出来一个。所以每次所有的交点的之间的区域的数量的增加量就为(交点的数量 - 1) ,那么交点的数量的增加量到底是多少呢?因为是一个折线(在这里我们可以将其近似考虑成两条直线),下面大家考虑以下“一条直线与n条直线能有几个交点?"答案必然是n个 ,所以当一个折线就可以形成2*n(这里的n表示的是n条直线,所以对于原题的来说一条折线与n条折线的交点数目就为2*(2*n))个交点,所以第n条折线所有交点间比第n-1的折线的区域数量增加了4*(n-1) - 1 (交点的数量 - 1 )块,另外需要注意的是,这是一条折线,所以当与其他的线相交过后必然会在其两端都形成一条射线,这两条射线也是能够将区域分割开的,所以分割的增加量除了前面交点形成的增加量意外,还有这两个射线的增加的  2  块。
           故有f(n) = f(n-1) + 4 * (n-1) - 1 + 2, 化简得  f(n) = (n-1) + 4 * n - 3;

(此段话是从别的博客里截下来的,详见地址:传送门)

核心代码:

cin >>m;
cout <<2*m*m - m + 1 <

Attack on Titans

题意:给出三种字符 G R P,要求组成一串长为n的字符,且要满足两个条件(至少连续M个G,至多K个连续R)问有多少种这样的字符串?

思路:首先题目给出了两个限制条件,一个至多,一个至少,不好去求解,便想到将至少转换成至多问题。

        (至少连续M个G)= (至多连续n个G)-(至多连续M-1个G)

统一以后,采用递推的思想来求解:求解至多u个G,至多v个R情况下,长度为n的字符串有多少种?

此处用dp[i][0、1、2] (第i个字符去0号,1号,2号字符时的情况,其中0代表G,1代表R,2代表P)

于是分三类情况讨论:令summ=dp[i-1][0] + dp[i-1][1] + dp[i-1][2];

 当第i个字符为P时:  dp[i][2]=summ;

当第i个字符为G时:若 i<=u 时dp[i][0]=summ;

                                 若i==u+1 dp[i][0]=summ-1;(前u个字符全为G的情况要减掉)

                                 若i>u+1    dp[i][0]=summ-dp[i-u-1][1]-dp[i-u-1][2];(前面有连续u个G字符的情况要减掉)

当第i个字符为R时:若 i<=v 时dp[i][1]=summ;          //同上

                                 若i==v+1 dp[i][1]=summ-1;

                                 若i>v+1    dp[i][1]=summ-dp[i-v-1][1]-dp[i-v-1][2];

故而,核心代码为:

long long Cal()
{
    dp[0][0]=1;
    dp[0][1]=0;
    dp[0][2]=0;
    for(int i=1;i<=n;i++)
    {
        long long sum=(dp[i-1][0]+dp[i-1][1]+dp[i-1][2])%M;
        dp[i][2]=sum;
        if(i<=u)
            dp[i][0]=sum;
        else if(i==u+1)
            dp[i][0]=(sum-1)%M;
        else
            dp[i][0]=(sum-dp[i-u-1][1]-dp[i-u-1][2])%M;
        if(i<=v)
            dp[i][1]=sum;
        else if(i==v+1)
            dp[i][1]=(sum-1)%M;
        else
            dp[i][1]=(sum-dp[i-v-1][0]-dp[i-v-1][2])%M;
    }
    return (dp[n][0]+dp[n][1]+dp[n][2])%M;
}

emmmm持续更新中,在DP这条漫漫长路上缓慢行驶。。。。。


 

 

 

你可能感兴趣的:(DP 合集)