POJ 1925 Spiderman [DP]
题意:略。
思路:大家多看看题目当中这个图
发现每次蜘蛛侠在空中发射蛛丝的位置都是与起点公寓的高度相同的(高中物理机械能守恒)。因此这个高度就不用计算了。
题目的重点是想出dp的递推公式。
现在先考虑一个问题,已知一栋大楼j的高度和x轴坐标和起点公寓的高度(公寓高度决定了蜘蛛侠发射蛛丝的高度),在x轴坐标多少范围内蜘蛛侠可以成功发射蛛丝荡过该大楼呢?
考虑极限情况,蜘蛛侠荡到最低点时正好贴着地面,则此时蛛丝的长度为大楼j的高度h[j]。则在距离地面高度为h[1](起点公寓的高度)时蜘蛛侠发射了该蛛丝,此时与大楼j的水平距离为
sqrt(h[j] ^ 2 - (h[j] - h[i]) ^ 2)
设该点为st,大楼j的x坐标为ed,则在x坐标为[st, ed),高度为h[1]时可成功发射蛛丝。
且由于对称,下次发射蛛丝时位置的横坐标为 ed + (ed - st) 即 2 * ed - st。
此时,dp比较容易想了。用dp[i]表示在横坐标为i处蜘蛛侠发射蛛丝的最少次数。设变量 dest = 2 * ed - st,
则 dp[dest] = min(dp[dest], dp[st] + 1)。
另外题目有两种临界情况需要注意,一是在计算建筑物可接受蛛丝区间[st, ed)时,st值最小不能小于起点公寓的x坐标(因为蜘蛛侠就是从这里出发的);二是在计算dest时,如果dest 大于最后一栋建筑的x坐标,表示它已经到达了终点,这个时候不在需要维护dp数组,直接通过结果变量res维护结果最小值,即此时有 res = min(res, dp[st] + 1)。
1 #include<stdio.h> 2 #include<iostream> 3 #include<string.h> 4 #include<algorithm> 5 #include<math.h> 6 #define inf 0x3f3f3f3f 7 using namespace std; 8 struct build 9 { 10 int ac, h, pos; 11 }b[5005]; 12 int dp[1000005]; 13 int main() 14 { 15 int t; 16 //freopen("data.in", "r", stdin); 17 scanf("%d", &t); 18 while (t--) 19 { 20 memset(dp, 0x3f, sizeof(dp)); 21 int n; 22 scanf("%d", &n); 23 for (int i = 1; i <= n; i++) 24 { 25 scanf("%d%d",&b[i].pos, &b[i].h); 26 b[i].ac = max(0, (int)ceil(b[i].pos - sqrt(2. * b[i].h * b[1].h - 1. * b[1].h * b[1].h))); 27 } 28 int res = inf; 29 dp[b[1].pos] = 0; 30 for (int i = 2; i <= n; i++) 31 { 32 int st = b[i].ac, ed = b[i].pos; 33 for (int j = st; j < ed; j++) 34 { 35 int dest = 2 * ed - j; 36 if (dest < b[n].pos) dp[dest] = min(dp[dest], dp[j] + 1); 37 else res = min(res, dp[j] + 1); 38 } 39 } 40 printf("%d\n", res == inf ? -1 : res); 41 } 42 return 0; 43 }