noip提高组写题心得——动态规划4例

时间:2021-06-24 16:44:50

题目1:Luogu P1970花匠:

最简单的一道题目。本题的重点在于如何理解

条件 A:对于所有g(2i)>g(2i-1),g(2i)>g(2i+1)

条件 B:对于所有g(2i)<g(2i-1),g(2i)<g(2i+1)

这两个东东。

看上去很深奥,实际上细想,就是从一个有序整数集合Q中顺序取出几个数组成一个数列,使得:这个数列一大一小就得了。要求这个数列最长。理解了一大一小这个东西,动态方程不难列出来,有两个,而因为每个f[i]只与f[i-1]有关,并且最终解是f[n]所以可以再进行状态压缩。连数组都不用,自己推一下就OK了

题目2:Luogu P1941 飞扬的小鸟:

这是动态规划中一道比较烦的题目。需要转移状态是非常明显的。所以为何这题是动态规划再次不多赘述。主要是细节。下面是

条件梳理:

1.小鸟始终在游戏界面内移动。小鸟从游戏界面最左边任意整数高度位置出发,到达游戏界面最右边时,游戏完成。

游戏完成的标志

 

2.小鸟每个单位时间沿横坐标方向右移的距离为1,竖直移动的距离由玩家控制。如果点击屏幕,小鸟就会上升一定高度X,每个单位时间可以点击多次,效果叠加;如果不点击屏幕,小鸟就会下降一定高度Y。小鸟位于横坐标方向不同位置时,上升的高度X和下降的高度Y 可能互不相同。 小鸟高度为m 时,无法再上升。这里的话我把这句话也放了进来,因为这些都是转移的条件。

 

3.游戏界面是一个长为n ,高为 m 的二维平面,其中有k 个管道(忽略管道的宽度)。小鸟高度等于0 或者小鸟碰到管道时,游戏失败。

这些都是游戏的边界。

 

4.现在,请你判断是否可以完成游戏。如果可以 ,输出最少点击屏幕数;否则,输出小鸟最多可以通过多少个管道缝隙。

这是要求的东西。

条件分析:(构造方程)

1和4告诉我们:可以使用f[i][j]来表示状态,表示小鸟飞到i,j坐标时最小的屏幕点击次数,而如果飞不过去,那么必定有一个坐标i,使得f[i][j](1<=j<=m)=0x7fffffff;这里可以得到初始化和解题的方向即f[i][j]=0x7ffffff(1<=i<=n;1<=j<=m)f[0][i]=0(1<=i<=m)

通过2可以构造方程。2 又可以分成以下几点:

1.小鸟每个单位时间沿横坐标方向右移的距离为1 ,竖直移动的距离由玩家控制。如果点击屏幕,小鸟就会上升一定高度X ,每个单位时间可以点击多次,效果叠加;如果不点击屏幕,小鸟就会下降一定高度Y 。->f[i][j]=min(f[i][j],min(f[i-1][j-x[i]],f[i][j-x[i]])+1);

注意:这里的x[i]表示的是一次能在i-1上跳几格。这里还蕴含着一个背包的思想。而且这个方程吧背包顺便初始化了。为何?首先,实际上吧每一列看成一个完全背包,而物品只有一个,可以无限次的取。可是一开始f[i][j]全部是MAX_INT,如果直接使用背包的写法,涉及到初始化,而且注意,这里并非是完整的背包问题,因为还可以从上一格的任意一个地方跳上来,即状态f[i][j]还与状态f[i-1][j]有关。所以这里干脆把f[i-1][j-x[i]]+1这个状态也加入了进来,从而得出了这样一个方程式。这个是本题难点。

小鸟高度为 m 时,无法再上升。此时再次得到一个方程

f[i][m]=min{f[i][m],f[i-1][j]+1}

然后至于管道,再每轮dp之后吧对应状态赋值成MAX_INT就OK了

总结:

本题最难的地方在于,能够联想的背包,然后类比背包构造方程。为啥用背包?因为条件之中的:如果点击屏幕,小鸟就会上升一定高度X,每个单位时间可以点击多次,效果叠加。这里的效果叠加,也就是一次dp可以无限次地跳跃达到向上的状态,这就是完全背包,但是由于二维状态转移与一维有关,即不一定要在本格之内飞,可以从上一格飞到这一格,所以多加一个f[i-1][j-x[i]]+1这个状态。

题目3:乌龟棋:

这题一开始想到的应该是暴搜,然而枚举所有卡片的顺序明显暴,根本不可行,我们得另想方法。此时,发现,乌龟只能向前爬,而且能得到分数,分数要求最大,因此可以使用动态规划。

非常容易列出一个方程:f[i][j][k][l][m]=max(f[i-1][j-1][k][l][m],f[i-2][j][k-1][l][m],f[i-3][j][k][l][m],f[i-4][k][l][m])+a[i];

f[i][j][k][l][m]表示乌龟爬到第i格使用j张数字为1的爬行卡片,k张数字为2的爬行卡片……

然而空间复杂度是O(n*40^4)无法接受,但是我们发现时间复杂度和空间复杂度相同,可以接受,所以只需降维就OK

此时有两种办法:第一种是使用滚动数组,因为f[i]只与f[i-4]有关,所以可以吧空间复杂度降到(4*40^4)

第二种,类比我们的01背包,我们发现,实际上f[i]根本不需要。因为f[i]之前 的状态要转移到f[i]都只需加上a[i],就是说其转移的操作是一样的,所以可以降维,但是i还是要从1~n进行循环的,只不过省去了这个空间。

总结:

此题不难,关键是如何把这个空间复杂度减下去,反正我就是卡在了空间上,没有想到可以降维。列方程真心不难。

题目4:引水入城:

烦+难的一道题。做题过程中,发现难题实际上是会进行分类的。即答案可能有两种,两种答案有联系,又是不同的方法得出的。此题就是这种类型。

思路确定:

一开始想到的仍然是枚举。枚举所有的建造水站的方法。那么如果从头搜到尾O(2^m*n*m)爆炸!

进一步思考,如果我先搜索能不能到达,即吧前面全部建水站,然后bfs,是O(n*m)完全可以接受

然后我一开始想到的是从尾部往前搜,但是没有想出来,最终还是没有实现,然后就去看题解了。题解的方法真心妙!

方法:

首先第一点,我们知道,要求最少的建水厂对吧?那么最少这个条件如果不用暴搜,以我们人的思维(贪心的角度)看看,很明显,哪个水厂能够滋润到的沙漠城市最多,哪个水厂就要优先考虑。虽然这个思维不够严谨,但是仍然能为我们提供方向。有时候,在考虑计算机的题目的优化解的时候,要多去以人的思维思考,以贪心的角度看问题,有可能为你提供方向。

既然将问题转化到哪个水厂流到哪里,我们就可以试试看枚举每一个水厂能够到达那些沙漠城市,可以做成。这里接下去又会被卡住一下。发现如果要是这些城市完全没有任何分布的规律的话,这题还是只能用最开始的暴搜的方法。此时我们就要开始考虑,这些水域是否有规律性。然后才有可能得出结论:一个水站能滋润到的沙漠城市必定为连续的。即其是一段区域。证明如下:

假设A点能到达的第n排的点不连续,其中点D无法到达,由于第一排的m个点能够通过“从高往低”的规则到达第n排所有点,故必定存在点B,A点不能到达,它能到达点D。此时,B点到达D点的路径必定和A点能到达的点相交,设为C点,那么此时A点可以通过AàCàD来到达D,与假设矛盾。}

证毕。既然是有区域的,那么本题就转化成为了区域覆盖问题,动态规划就好列了。不再解释,直接贴方程:

F[i]=min{f[l[j]-1]+1} (l[j]<=i && l[r]>=i)

本题难点:

思维转化过程:有两个

(1)如何想到先搜后动归(如何把题目变成两个part)

(2)如何想到流水的规律

动态规划最终总结:

1.  一般过程:

(1)确定可以使用动归(判断依据:1.最优解2.线性3.状态变化4.不可逆)

(2)分析状态转移条件

(3)列方程(注意范围)

(4)优化

(5)出解

2. 类型:

这里的类型并非指动态规划的数据结构类型,而是只动态规划难易程度上的类型。

(1)难想到的类型。(方法:熟练掌握动态规划的使用原理,使用条件,即了解动态规划是干什么的)

(2)难列方程的类型。(方法:状态分析,条件分析很重要。对于多种复杂状态的整理。还要夹杂着一些特殊的思想(比如背包,区间等等))

(3)优化难的方程。(真正的难题,优化一般有一下几种方法)

① 降维:滚动数组、直接降维。(处理空间复杂度不够的)

② 预处理:比如前缀数组等等之类的(处理时间复杂度不够的)

③ 二分:矩阵优化等。(仍是处理时间复杂度不够的)