poj-1925 Spiderman

dp

d[i] 表示从apartment到 横坐标 i 最少需跳几步。。  p[i] 建筑物 i 的横坐标, h[i]建筑物i的纵坐标

注意 由对称性,spiderman的纵坐标始终是 apartment 的高度!! 所以不需要管纵坐标!!

遍历每个建筑物。。   

  从横坐标 j 能跳过建筑物 i 需满足: (p[i] - j)^2 <= h[i] ^ 2  - (h[i] - h[1]) ^2

      从横坐标 j 经建筑物 i 后 到达横坐标 2 * p[i] - j。。

  综上, d[2 * p[i] - j] = min(d[2 * p[i] - j] , d[j] + 1)...

最后注意到达west tower的步数的处理

/*
 * 1925.cpp
 *
 *  Created on: 2011-7-8
 *      Author:
 */
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;

const int MAXN = 5000 + 5;
const int MAX_X = 2000000 + 5;
const int INF = 1000000;

int n;
int p[MAXN], h[MAXN];
double scale[MAXN];
int d[MAX_X];

int main(){
    int tot;
    scanf("%d", &tot);
    while(tot--){
        scanf("%d", &n);

        for(int i=1; i<=n; i++){
            scanf("%d%d", &p[i], &h[i]);
    //        scale[i] = sqrt((double) h[i] * h[i] - (h[i] - h[1]) * (h[i] - h[1]));    //注意不要用sqrt,否则TLE!!  (后面比较的时候用平方)
      scale[i] = h[i] * h[i] - (h[i] - h[1]) * (h[i] - h[1]);
        }

        memset(d, -1, sizeof(int) * MAX_X);  //也可以for循环。。 d[i] = INF  为了节省时间,直接设为-1, 之后判断。。
        d[p[1]] = 0;

        //……
        for(int i=2; i<=n; i++){
            for(int j = p[i]-1; j>=p[1]; j--){
                if(d[j] == -1) continue;        //!!!!  直接跳过~

                int gap = p[i] - j;
                if(gap * gap> scale[i]) break;  //gap的平方和scale比较

                int aim =  2*p[i]-j;
                if( (d[ aim ]==-1 || d[ aim ] > d[j] + 1) ){
                    d[ aim ] = d[j] + 1;
                }

                if(aim >= p[n] && (d[p[n]] == -1 || d[p[n]] > d[ aim ])){  //最后的处理
                    d[p[n]] = d[ aim ];
                }
            }
        }


        if(d[p[n]] <= 0)
            printf("-1\n");
        else
            printf("%d\n", d[p[n]]);

    }

    return 0;
}



你可能感兴趣的:(spider)