【poj 1925】Spiderman 题意&题解&代码(C++)

题目链接:

http://poj.org/problem?id=1925

题意:

输入K组数据,每组数据输入n个柱子的信息,每个柱子信息为x坐标和高度h,蜘蛛侠需要从第一的柱子通过不断荡蛛丝荡到最后一个柱子,荡的规则:
1.蜘蛛侠不会撞到柱子上,假如他在高度为h的位置j通过柱子i前进,那么它会直接荡到同样高度为h位置为x[i]+x[i]-j的位置上,不会受中间柱子的阻挡(x[i]表示柱子i的x坐标)
2.蜘蛛侠在荡蛛丝的过程中一旦能荡到位置x,使得x>=x[n],则视为它荡到了最后一个柱子上(只适用于最后一个柱子)。
求最少的荡蛛丝的次数。

1 <= T <= 20,0 <= Xi, Yi <= 1000000,2 <= N <= 5000

题解:

注意它给出了初始的高度,每次荡完之后所处位置的高度与初始高度相同,因此高度仅仅用来判断能否荡蛛丝,对于状态转移并没有影响。

首先不考虑数据范围,我们很快可以想出一个N×X[n]的做法,类似于01背包,dp[j]表示到达位置j时所荡的最少次数,转移方程和01背包也没太大区别

        for (int i=1;i<=x[n];i++)
        dp[i]=55555; 
        dp[0]=0;
        for (int i=2;i<=n;i++)
        for (int j=0;j<=x[i];j++)
        if (dp[j]!=55555&&pan(i,j))
        {
            int nex=min(x[i]+x[i]-j,x[n]);
            dp[nex]=min(dp[nex],dp[j]+1);
        }

然而这样的时间复杂度妥妥的超时,参考了一下题解,我们发现每个柱子所能更新的区间范围是一定的(因为蛛丝的长度要求),范围的大小len

            int len=pow(h[i],2)-pow(h[i]-h[1],2);
            len=sqrt(len);

从( 0 , x[i]-len )这部分是根本不能通过柱子i往前荡的,这部分没用的枚举浪费了很多时间复杂度,那么我们每次从(x[i]-len)的位置开始枚举到x[i]即可,虽然感觉这样会有数据能够使它卡掉,因为按数学式子写时 len^2=(hi^2)-(hi-h0)^2,我们发现当hi和h0都最大且相近时,时间还是会超时,然而加了这优化后至少poj是能过的,醉了。

代码:

#include
#include
#include
#include
#include
#include
using namespace std;
int T,n,x[5005],h[5005],dp[1000005];
bool pan(int i,int w)
{
    if (pow(h[i],2)>=pow(x[i]-w,2)+pow(h[i]-h[1],2)) return 1;
    return 0;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
        scanf("%d%d",&x[i],&h[i]);
        for (int i=1;i<=x[n];i++)
        dp[i]=55555; 
        dp[0]=0;
        for (int i=2;i<=n;i++)
        {
            int len=pow(h[i],2)-pow(h[i]-h[1],2);
            len=sqrt(len);
            for (int j=max(x[i]-len,0);j<=x[i];j++)
            if (dp[j]!=55555&&pan(i,j))
            {
                //这里之所以加pan(i,j)是因为担心精度处理出问题,去掉之后会WA
                int nex=min(x[i]+x[i]-j,x[n]);
                dp[nex]=min(dp[nex],dp[j]+1);   
            }
        }
                if (dp[x[n]]!=55555)
            printf("%d\n",dp[x[n]]);         
                else printf("-1\n");
    }
}

你可能感兴趣的:(oi之路,poj)