From 8ca1abca0b776fcab80f87e40949ca1f57348197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B5=B7?= <10402852@qq.com> Date: Tue, 5 Mar 2024 15:37:14 +0800 Subject: [PATCH] 'commit' --- .../NumberTriangles/数字三角形专题.md | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 TangDou/AcWing_TiGao/T1/NumberTriangles/数字三角形专题.md diff --git a/TangDou/AcWing_TiGao/T1/NumberTriangles/数字三角形专题.md b/TangDou/AcWing_TiGao/T1/NumberTriangles/数字三角形专题.md new file mode 100644 index 0000000..92b4bf6 --- /dev/null +++ b/TangDou/AcWing_TiGao/T1/NumberTriangles/数字三角形专题.md @@ -0,0 +1,94 @@ +## 数字三角形 【干货、背诵版】 + +#### 基础题 + +**[$AcWing$ $1015$. 摘花生](https://www.acwing.com/problem/content/1017/)** + +二维状态表示,双重循环填充二维表,从上或右可以转移 +```cpp {.line-numbers} + for (int i = 1; i <= n; i++) + for (int j = 1; j <= m; j++) + // 递推的出发点,采用特判的办法手动维护,其它的靠关系式递推完成 + // 之所以这样对起点进行初始化,是因为只有这样才能保障逻辑自洽 + if (i == 1 && j == 1) + f[i][j] = w[i][j]; + else + f[i][j] = max(f[i - 1][j], f[i][j - 1]) + w[i][j]; + +``` +初始值 +```cpp {.line-numbers} + f[1][1] = w[1][1]; //出发点 +``` +① **状态表示** +$f[i][j]$代表走到第$(i,j)$个位置时可以获取到的最大数量和 + +② **状态转移** +即$f[i][j]$可以从哪些状态转移而来 + +③ **初始值** +思考起点下状态表示的现实含义即可 + +**总结** +① 动态规划需要按上面的三步走,而最难的是状态表示,状态转移还好,根据题意可以推出相应的转换关系。状态表示一般是通过 **经验**,对,是 **经验**。 + +② 初始值:不一定非得放在循环外进行初始化,也可以合并在循环内,有时放在循环内初始化反而更方便更直接。 + +③ 可以使用一维表示,但我个人理解不如二维的直观,最起码思路应该是先有两维再缩成一维,而不是上来就直接一维。一般的题目不会对内存有严格的限制,能用二维还是二维吧,实在卡内存再考虑降为一维。 + + +**[$AcWing$ $1018$. 最低通行费](https://www.acwing.com/problem/content/1020/)** +与上一题基本一样,只不过是变换了下,需要你用思维转一下:$2n-1$次,就是说只能向下或向右,否则次数就不达标了。还有一点,就是需要求最小值,而不是最大值,其它的没区别 +```cpp {.line-numbers} +//初始化为最大值 +memset(f, 0x3f, sizeof f); + +for (int i = 1; i <= n; i++) + for (int j = 1; j <= n; j++) { + if (i == 1 && j == 1) + f[i][j] = w[i][j]; //特事特办,不用追求完美的一体化表现,合理特判,逻辑简单 + else + f[i][j] = min(f[i - 1][j], f[i][j - 1]) + w[i][j]; + } +``` + +#### 进阶题 + +**[$AcWing$ $1027$. 方格取数](https://www.acwing.com/problem/content/1029/)** +走两次,其实是故意让我们真的走两回,每次取最优。 + +很明显,这是坑。因为如果每次走时不考虑别人,只考虑自己,就是局部最优,不是全局最优,这样就是贪心,不是动态规划。 + +解决办法就是把两次一起考虑,转化为有两个小人一起走,步调一致,此时两个相亲相爱,互相照顾,白头偕老,皆大欢喜: + +状态表示也就呼之欲出: +$f[x_1][y_1][x_2][y_2]$表示第1个人走到$(x_1,y_1)$,第2个人走到$(x_2,y_2)$,但需要保证$x_1+y_1=x_2+y_2$ + +**状态转移**: +① 如果两个人走到同一个位置,就可能加上一次这个位置上的数 +② 如果两个人走到不同的位置,就可以加上两个地方上的数 +③ 两个坐标共同决定了现在的状态,换句话说,状态和上面的两个坐标都是相关的 + + +```cpp {.line-numbers} + //开始递推 +for (int x1 = 1; x1 <= n; x1++) + for (int y1 = 1; y1 <= n; y1++) + for (int x2 = 1; x2 <= n; x2++) + for (int y2 = 1; y2 <= n; y2++) { + if (x1 + y1 == x2 + y2) { + int t = f[x1 - 1][y1][x2 - 1][y2]; //下下 + t = max(t, f[x1][y1 - 1][x2][y2 - 1]); //右右 + t = max(t, f[x1 - 1][y1][x2][y2 - 1]); //下右 + t = max(t, f[x1][y1 - 1][x2 - 1][y2]); //右下 + //加上这个点的数值 + f[x1][y1][x2][y2] = t + w[x1][y1]; + //如果这个点没有被重复走,那么再加一次w(x2,y2) + if (x1 != x2 && y1 != y2) f[x1][y1][x2][y2] += w[x2][y2]; + } + } +``` + + +**[$AcWing$ $275$. 传纸条](https://www.acwing.com/problem/content/277/)** +与上面的题目是一个题。 \ No newline at end of file