第三章上机实践报告
7-3 最低通行费
这题只要知道每个点的前一个点只能是左侧或者上侧相邻的点就基本没什么问题了,初始化的时候第一行只能由左侧到达,第一列只能由上侧到达。
for(int i = 1; i <= n; i++) { f[1][i] += f[1][i-1]; f[i][1] += f[i-1][1]; } for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { f[i][j] += min(f[i-1][j], f[i][j-1]); } }
7-1 最大子段和
就是一个求连续最大前缀的问题,当(前一个数)的前缀小于零,就从当前数从头开始求前缀,求完所有可能的最大连续前缀,然后再遍历一遍找到最大值就行了。
int res = 0; for(int i = 1; i < n; i++) { if(a[i - 1] < 0) a[i - 1] = 0; a[i] += a[i-1]; } for(int i = 0; i < n; i++) res = max(res, a[i]);
7-2 单调递增最长子序列
对每个数字都求以这个数为结尾的最大上升序列长度,最后再遍历一遍找到最大值输出就行,初始化每个数都至少可以组成一个长度为 1 的数组。
for(int i = 0; i <= n; i++) f[i] = 1; for(int i = 1; i <= n; i++) { for(int j = 1; j < i; j++) { if(g[i] > g[j]) f[i] = max(f[i], f[j] + 1); } } int res = 0; for(int i = 1; i <= n; i++) res = max(res, f[i]);
7-4 最短编辑距离
有字符串 a 和 字符串 b
对 a 增加,删除,修改使之变为b,求最小操作数。
f[i][j]:a 的前 i 个 --> b 的前 j 个的最小操作数
在操作 f[ i ][ j ] 时,a的前 (i - 1) 个,b的前 (j - 1) 个已经匹配好了
删除:a 比 b 多一个 f[i][j - 1]
增加:a 比 b 少一个 f[i - 1][j]
修改:a[i] != b[j]
for(int i = 0; i <= n; i++) f[i][0] = i; for(int j = 0; j <= m; j++) f[0][j] = j; for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++){ //增加和删除 f[i][j] = min(f[i-1][j], f[i][j-1]) + 1; if(a[i] == b[j]) f[i][j] = min(f[i][j], f[i-1][j-1]); //修改 else f[i][j] = min(f[i][j], f[i-1][j-1] + 1); }
总结:总的来说都是比较经典的题目,除了最短编辑距离难度相对大一些外,其他三题都比较简单。