poj-1925

22 篇文章 0 订阅
//4380K 469MS   G++
#include <cstdio>
#include <cstring>
#include <cmath>

using namespace std;

const int MAX = 1000005;

int buildingNum;

struct Building {
    long long x; //notice! should use long long
    long long y;
};

int DP[MAX];

typedef struct Building Building;

int caseNum;

Building buildings[5005];

int min(int a, int b) {
    return a < b? a: b;
}

void getMinSwing() {
    DP[buildings[1].x] = 0;
    for (int i = 2; i <= buildingNum; i++) {
        int dis = sqrt(buildings[i].y*buildings[i].y 
            - (buildings[i].y - buildings[1].y)*(buildings[i].y - buildings[1].y));
        for (int j = 1; j <= dis; j++) {
            if (buildings[i].x - j >= 0) {
                int dest = min(buildings[buildingNum].x, buildings[i].x + j);

                if (DP[buildings[i].x - j] != -1) {
                    if (DP[dest] != -1) {
                        DP[dest] = min(DP[buildings[i].x - j] + 1, DP[dest]);
                    } else {
                        DP[dest] = DP[buildings[i].x - j] + 1;
                    }
                }
            } else {
                break;// the left no need check, still < 0
            }
        }
    }
    printf("%d\n", DP[buildings[buildingNum].x]);
}

int main() {
    scanf("%d", &caseNum);
    for (int i = 1; i <= caseNum; i++) {
        memset(DP, -1, sizeof(DP));
        memset(buildings, 0, sizeof(buildings));
        scanf("%d", &buildingNum);
        for (int j = 1; j <= buildingNum; j++) {
            scanf("%lld %lld", &(buildings[j].x), &(buildings[j].y));
        }
        getMinSwing();
    }
}

http://www.2cto.com/kf/201208/148332.html

http://blog.csdn.net/lin375691011/article/details/28133407

转化难的DP题,打死我都想不到这种解题思路,拜服了.

基本思路是这样的:

首先,根据题意,蜘蛛侠在swing时,只有荡到最高点的时候才能进行下一次swing,而根据钟摆原理,蜘蛛侠从(x1, y1) swing到最高点 (x2,y2)时,  y1 一定是等于y2的, 因此,得到了一个可以大大简化题目的点: 即蜘蛛侠在这么多次swing中,每个中间点(也是swing的最高点)的 y 都是一样的,并且题目还指明了apartment的 y 是builing中最小的y值(这个后面会用到), 我们只需要考虑x坐标的变化即可,即DP数组可以直接开成一维的, DP[N]即可, DP[i]代表 从apartment起始点荡到x == i的位置,所需要的最小swing数。

那么下面这样做:

对除了apartment之外的所有building的每个成员 i, 求出在蜘蛛侠不会及地的前提下,可以在i swing的起始点,

那么为了不及地, 蜘蛛侠swing的最长半径就是building i的高度, 

而在最长半径前提下, swing起始点的x坐标与 i的x的坐标之间的距离dis就利用直角三角形的变长关系得到:

dis = sqrt(buildings[i].y*buildings[i].y 
     <span style="white-space:pre">		</span>- (buildings[i].y - buildings[1].y)*(buildings[i].y - buildings[1].y));
注意,因为在解题时忽略了y坐标,但是,在求该距离时,是需要考虑y坐标的。

那么在不及地的前提下,从 i开始swing的起始点的范围在x坐标就是 [buildings[i].x - dis,   buildings[i].x - 1 ]

而每个起始点,其swing的结束点则是相对 [buildings[i].x对称的, 即 [buildings[i].x + 1,  buildings[i].x + dis],

然后就对 [buildings[i].x - dis,   buildings[i].x - 1 ] 每个整数值 k 进行处理:

首先看 k是否小于0, 如果是,直接break了,

然后看DP[k]是否为-1(无效情况, 即根本不可能荡到x==k点),如果是,跳过这个k,continue

如果DP[k]有有效解,那么就可以进行DP递推了, 不过有个重要的一点,

设起始点k的对应的结束点是 p, 那么因为最后目的地是最后一个buildg[N]的x坐标(不要求超出此值), 因此

如果p超过了buildg[N].x , 那么此次swing的目的地x要按照buildg[N].x算,这样保证了最后一次swing的正确。

设经过上面逻辑的结束点是t, 那么

如果DP[t] == -1(之前还没有过有效解),那么直接覆盖DP[t]

否则,还要取 DP[k] + 1(从k swing了一次) 和 DP[t]的最小值.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值