## 【总结】动态规划的具体路径输出 ### 一、解决的问题 在取得了动态规划的极值或最优解之后,要求输出具体的路径。 ### 二、解决思路 反向查找转移路径,从最后状态出发,检查所有前序状态,看看是从哪个状态转移过来的,一直到出发点为止。 $dfs$法,路径是反的,需要倒序输出。 倒序循环法,没有这个问题,可以正序输出。 ### 三、$dfs$后序输出法【推荐】 **致敬墨染空大神** 优点:代码短,好理解,充分利用了递归的堆栈完成了倒序输出。 ```c++ void out(int i, int j) { if (i == 0) return; //走出界就完事了 int k = path[i][j]; out(i - 1, j - k); //利用递推的栈机制,后序输出,太强了~ printf("%d %d\n", i, k); } // 调用示例: for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) scanf("%d", &w[j]); for (int j = m; j; j--) for (int k = 1; k <= j; k++) { int val = f[j - k] + w[k]; if (val > f[j]) { f[j] = val; //在状态转移时,记录路径 path[i][j] = k; } } } //输出结果 printf("%d\n", f[m]); //输出路径 out(n, m); ``` ### 四、倒序循环法 ```c++ int j = m; // j开始枚举每个可用空间 for (int i = n; i >= 1; i--) // 倒序遍历dp数组 for (int k = 0; k <= j; k++) // f[i][j]是从哪个前序状态f[i-1][?]转移而来 if (f[i][j] == f[i - 1][j - k] + w[i][k]) { path[i] = k; //记录路径 j -= k; //减少体积 break; //找到一组即可 } //输出路径 for (int i = 1; i <= n; i++) printf("%d %d\n", i, path[i]); ``` ### 五、普通$dfs$法 ```c++ //反向查找转移路径:dfs法 int path[N], idx, id; void dfs(int i, int j) { if (i == 0) return; for (int k = 0; k <= j; k++) { if (f[i - 1][j - k] + w[i][k] == f[i][j]) { path[++idx] = k; dfs(i - 1, j - k); return; } } } //调用 dfs(n, m); for (int i = idx; i; i--) printf("%d %d \n", ++id, path[i]); ```