求助:Waterfall Rock Hit问题的动态规划实现与代码补全
解决Waterfall Rock Hit问题:补全判断逻辑与去重机制
嘿,我看你在处理这个课堂动态规划题时卡在了岩石击中判断和重复计数的地方,咱们一步步拆解问题,把代码补全理顺:
首先理清楚核心逻辑的误区
1. 排序方向搞反了
水是从高处往低处下落的,咱们得先处理位置更高的岩石,这样在下落检测时才会优先碰到上方的岩石,避免漏判或重复计数。你原来的排序是升序,得改成降序:
bool acompare(a lhs, a rhs){ return lhs.v1 > rhs.v1; // 按岩石顶部高度从高到低排,高处的先检测 }
2. 边界条件不对
你的边界判断x == n || y == m || y == -1不符合实际下落逻辑:当水落到瀑布底部(x<0)或者流出左右边界(y<0或y>=m)时,就不会再击中任何岩石了,所以正确的边界应该是:
if (x < 0 || y < 0 || y >= m) { return 0; }
补全岩石击中的判断逻辑
水垂直下落时,要找当前y列里,离自己最近的那块岩石(也就是位置最高的下方岩石)。具体要满足三个条件:
- 岩石的水平范围覆盖当前的y坐标
- 岩石在水的当前位置下方
- 岩石还没被计数过
把这个逻辑写成代码,替换你原来的else if()空块:
int hit_idx = -1; for(int i=0; i<nstone; i++){ // 检查:未被计数、水平包含当前y、岩石在当前x下方 if(!arr[i].pass && arr[i].h1 <= y && y <= arr[i].h2 && arr[i].v1 < x){ // 筛选出离当前位置最近的岩石(顶部最高的) if(hit_idx == -1 || arr[i].v1 > arr[hit_idx].v1){ hit_idx = i; } } } if(hit_idx != -1){ // 标记为已计数,避免重复统计 arr[hit_idx].pass = true; // 分流:从岩石的左右端点,从岩石顶部的下方向下落 return 1 + fall(arr[hit_idx].v1, arr[hit_idx].h1) + fall(arr[hit_idx].v1, arr[hit_idx].h2); }
完整修正后的代码
把所有调整整合起来,完整代码如下:
#include <iostream> #include <algorithm> using namespace std; int n, m, nstone; struct a{ int v1, v2, h1, h2; // v1:岩石顶部垂直坐标, v2:底部垂直坐标; h1:左水平坐标, h2:右水平坐标 bool pass; // 是否已被计数 }; a arr[5000]; // 按岩石顶部高度降序排序 bool acompare(a lhs, a rhs){ return lhs.v1 > rhs.v1; } int fall(int x, int y){ // 边界:流出瀑布范围,无法击中岩石 if (x < 0 || y < 0 || y >= m) { return 0; } // 查找当前下落路径中击中的岩石 int hit_idx = -1; for(int i=0; i<nstone; i++){ if(!arr[i].pass && arr[i].h1 <= y && y <= arr[i].h2 && arr[i].v1 < x){ if(hit_idx == -1 || arr[i].v1 > arr[hit_idx].v1){ hit_idx = i; } } } if(hit_idx != -1){ arr[hit_idx].pass = true; // 分流到岩石两端,从顶部下方向下落 return 1 + fall(arr[hit_idx].v1, arr[hit_idx].h1) + fall(arr[hit_idx].v1, arr[hit_idx].h2); } else { // 没有击中岩石,继续垂直下落 return fall(x-1, y); } } int main(){ cin >> n >> m >> nstone; for (int i=0; i<nstone; i++){ cin >> arr[i].v1 >> arr[i].h1 >> arr[i].v2 >> arr[i].h2; arr[i].pass = false; } sort(arr, arr+nstone, acompare); int start; cin >> start; // 水从(start, m)开始下落,对应题目描述的起始位置 cout << fall(start, m) << endl; return 0; }
测试样例验证
针对你给出的测试输入:
6 6 3 2 3 2 4 4 2 5 2 5 5 6 5 5
水从(5,6)开始下落,会依次击中三块岩石:
- 先垂直下落至岩石3的水平范围,击中后分流到左右端点继续下落
- 分流的水流分别击中岩石2和岩石1
- 所有岩石都被标记为已计数,最终返回3,和样例输出一致
内容的提问来源于stack exchange,提问作者InfinityGR
相关产品推荐
相关产品推荐

