zoukankan      html  css  js  c++  java
  • 洛谷 P2466 Sue的小球 解题报告

    P2466 [SDOI2008]Sue的小球

    题目描述

    Sue和Sandy最近迷上了一个电脑游戏,这个游戏的故事发在美丽神秘并且充满刺激的大海上,Sue有一支轻便小巧的小船。然而,Sue的目标并不是当一个海盗,而是要收集空中漂浮的彩蛋,Sue有一个秘密武器,只要她将小船划到一个彩蛋的正下方,然后使用秘密武器便可以在瞬间收集到这个彩蛋。然而,彩蛋有一个魅力值,这个魅力值会随着彩蛋在空中降落的时间而降低,Sue要想得到更多的分数,必须尽量在魅力值高的时候收集这个彩蛋,而如果一个彩蛋掉入海中,它的魅力值将会变成一个负数,但这并不影响Sue的兴趣,因为每一个彩蛋都是不同的,Sue希望收集到所有的彩蛋。

    然而Sandy就没有Sue那么浪漫了,Sandy希望得到尽可能多的分数,为了解决这个问题,他先将这个游戏抽象成了如下模型:

    以Sue的初始位置所在水平面作为(x)轴。

    一开始空中有(N)个彩蛋,对于第(i)个彩蛋,他的初始位置用整数坐标((xi, yi))表示,游戏开始后,它匀速沿(y)轴负方向下落,速度为(v_i)单位距离/单位时间。Sue的初始位置为((x0, 0)),Sue可以沿x轴的正方向或负方向移动,Sue的移动速度是1单位距离/单位时间,使用秘密武器得到一个彩蛋是瞬间的,得分为当前彩蛋的(y)坐标的千分之一。

    现在,Sue和Sandy请你来帮忙,为了满足Sue和Sandy各自的目标,你决定在收集到所有彩蛋的基础上,得到的分数最高。

    输入输出格式

    输入格式:

    第一行为两个整数(N), (x0)用一个空格分隔,表示彩蛋个数与Sue的初始位置。

    第二行为(N)个整数(x_i),每两个数用一个空格分隔,第(i)个数表示第(i)个彩蛋的初始横坐标。

    第三行为(N)个整数(y_i),每两个数用一个空格分隔,第(i)个数表示第(i)个彩蛋的初始纵坐标。

    第四行为(N)个整数(v_i),每两个数用一个空格分隔,第(i)个数表示第(i)个彩蛋匀速沿(y)轴负方向下落的的速度。

    输出格式:

    一个实数,保留三位小数,为收集所有彩蛋的基础上,可以得到最高的分数。

    说明

    对于30%的数据,(N<=20)

    对于60%的数据,(N<=100)

    对于100%的数据,(-10^4 <= xi,yi,vi <= 10^4,N < = 1000)


    从暴力开始

    我们发现,对于当前时间所处的每一个位置,我们有且仅有两个选择(即向左或向右)

    30分到手,(O(2^N))的复杂度。

    既然有向左或向右的选择,很容易联想到DP上去啊。

    (dp[i][j])代表已经处理左端为(i)号彩蛋和右端为(j)号彩蛋时的区间所产生的最大分数。

    试试写转移的话,我们会发现两个问题。

    1. 对于当前位置的信息我们需要存储一下,也就是在左端点还是右端点,多开一维维护即可。

    2. 对于彩蛋的分数,是和时间挂钩的,如果想完整的求解,得把时间压进去啊。

    时间压进去肯定爆了有没有别的办法呢?

    当然有,每一个点的最终得分其实不就等于 它的初始得分 减去 它的损失分 吗

    我们尝试维护这样一个损失分的最小值。

    对于 每一段转移的时候 我们都能求出 这段时间内 还没有得到的彩蛋的分的 损失值

    (dp[i][j][0]=min(dp[i+1][j][0]+(t[i+1].x-t[i].x)*(sumv[i]+sumv[n]-sumv[j]),)
    (dp[i+1][j][1]+(t[j].x-t[i].x)*(sumv[i]+sumv[n]-sumv[j]));)
    (dp[i][j][1]=min(dp[i][j-1][0]+(t[j].x-t[i].x)*(sumv[i-1]+sumv[n]-sumv[j-1]),)
    (dp[i][j-1][1]+(t[j].x-t[j-1].x)*(sumv[i-1]+sumv[n]-sumv[j-1]));)

    其中,(sumv[i])维护的是速度的前缀和数组。


    code:

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int N=1002;
    double x0,sumv[N],sumy;
    int n;
    double dp[N][N][2];
    double abs(double x) {return x>0?x:-x;}
    struct node
    {
        double x,y,v;
        bool friend operator <(node n1,node n2)
        {
            return n1.x<n2.x;
        }
    }t[N];
    int main()
    {
        scanf("%d%lf",&n,&x0);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                dp[i][j][0]=dp[i][j][1]=1e300;
        for(int i=1;i<=n;i++)
            scanf("%lf",&t[i].x);
        for(int i=1;i<=n;i++)
        {
            scanf("%lf",&t[i].y);
            sumy+=t[i].y;
        }
        for(int i=1;i<=n;i++)
            scanf("%lf",&t[i].v);
        sort(t+1,t+1+n);
        for(int i=1;i<=n;i++)
            sumv[i]=sumv[i-1]+t[i].v;
        for(int i=1;i<=n;i++)
            dp[i][i][0]=dp[i][i][1]=(abs(t[i].x-x0))*sumv[n];
        for(int i=n-1;i>=1;i--)
            for(int j=i+1;j<=n;j++)
            {
                dp[i][j][0]=min(dp[i+1][j][0]+(t[i+1].x-t[i].x)*(sumv[i]+sumv[n]-sumv[j]),
                                dp[i+1][j][1]+(t[j].x-t[i].x)*(sumv[i]+sumv[n]-sumv[j]));
                dp[i][j][1]=min(dp[i][j-1][0]+(t[j].x-t[i].x)*(sumv[i-1]+sumv[n]-sumv[j-1]),
                                dp[i][j-1][1]+(t[j].x-t[j-1].x)*(sumv[i-1]+sumv[n]-sumv[j-1]));
            }
        printf("%.3lf
    ",(sumy-min(dp[1][n][0],dp[1][n][1]))/1000.0);
        return 0;
    }
    

    我居然又在离散化(排序)之前求了(sumv),还找了许久的错啊。。。

    丢人。。


    2018.5.21

  • 相关阅读:
    11. Container With Most Water
    9. Palindrome Number
    375. 猜数字大小 II leetcode java
    leetcode 72 编辑距离 JAVA
    73. 矩阵置零 leetcode JAVA
    快速排序 JAVA实现
    63. 不同路径 II leetcode JAVA
    重写(override)与重载(overload)
    62 不同路径 leetcode JAVA
    leetcode 56 合并区间 JAVA
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9070010.html
Copyright © 2011-2022 走看看