写这篇博客是为了将这几天写的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这条漫漫长路上缓慢行驶。。。。。