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

  • 相关阅读:
    Rhythmk 一步一步学 JAVA(4):Spring3 MVC 之 Hello Word
    使用webclient同时post普通表单字段和文件表单字段数据到指定的URL【转】
    Rhythmk 一步一步学 JAVA(2) : 操作 MYSQL 数据库
    判断FLASH版本问题
    Rhythmk 一步一步学 JAVA(3): java JSON 数据序列化 以及反序列化
    Rhythmk 一步一步学 JAVA(5) Hibernate环境配置
    JS 数据存储
    文件下载 获取远程图片
    SQL SERVER 学习笔记
    AngularJS源码学习一 :directive
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9070010.html
Copyright © 2011-2022 走看看