1 条题解
-
1
题意分析
蜘蛛侠每天进行攀爬训练,每次训练由个阶段组成,每个阶段需要攀爬米。他可以选择向上或向下攀爬,但必须满足以下条件:
- 训练开始和结束时处于地面米处。
- 训练过程中不能低于地面米。
- 建筑物的高度必须至少比训练期间到达的最高点高出米。
我们需要找到一个合法的攀爬方案(用"U"和"D"表示),使得所需的建筑物高度最小。如果无解,输出"IMPOSSIBLE"。
解题思路
- 动态规划状态设计:设表示前个阶段结束时处于高度时的最小最大高度。
- 状态转移:
- 如果第阶段选择向上攀爬,则增加,且。
- 如果第阶段选择向下攀爬,则减少,且。
- 更新为当前最大高度和之前状态的最大高度的较小值。
- 路径记录:使用记录状态转移的前驱高度,以便回溯输出方案。
实现步骤
- 初始化:将数组初始化为无穷大,。
- 状态转移:
- 遍历每个阶段和可能的高度。
- 尝试向上或向下攀爬,更新和。
- 结果判断:
- 如果仍为无穷大,输出"IMPOSSIBLE"。
- 否则,回溯数组输出方案。
C++实现
#include <iostream> #include <string.h> #include <stdio.h> #include <algorithm> #include <math.h> #include <stdlib.h> using namespace std; #define MAX 10000000 int dp[45][1005]; int pre[45][1005]; int n; int a[45]; void dfs(int x,int height) { if(x==0) return; dfs(x-1,pre[x][height]); if(height>pre[x][height]) printf("U"); else printf("D"); } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } for(int i=0;i<=n;i++) for(int j=0;j<=1000;j++) dp[i][j]=MAX; dp[0][0]=0; for(int i=1;i<=n;i++) { for(int j=0;j<=1000;j++) { if(j-a[i]>=0&&dp[i-1][j-a[i]]!=MAX) { if(dp[i][j]>max(dp[i-1][j-a[i]],j)) { dp[i][j]=max(dp[i-1][j-a[i]],j); pre[i][j]=j-a[i]; } } if(j+a[i]<=1000&&dp[i-1][j+a[i]]!=MAX) { if(dp[i][j]>max(dp[i-1][j+a[i]],j)) { dp[i][j]=max(dp[i-1][j+a[i]],j); pre[i][j]=j+a[i]; } } } } if(dp[n][0]==MAX) printf("IMPOSSIBLE\n"); else { dfs(n,0); printf("\n"); } } return 0; }
代码说明
- 全局变量:
- :动态规划数组,记录前阶段高度的最小最大高度。
- :记录状态转移的前驱高度。
- :存储每个阶段的攀爬距离。
- 函数:回溯输出方案,根据数组判断每一步是向上("U")还是向下("D")。
- 主函数:
- 初始化数组为无穷大,。
- 遍历每个阶段和高度,尝试向上或向下攀爬,更新和。
- 判断是否有解,若无解输出"IMPOSSIBLE",否则回溯输出方案。
- 1
信息
- ID
- 2004
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者